pax_global_header00006660000000000000000000000064122264574140014521gustar00rootroot0000000000000052 comment=f8ce1cccd44f7b89b420562d7fa9f4c1a470e17c mdbtools-0.7.1/000077500000000000000000000000001222645741400133515ustar00rootroot00000000000000mdbtools-0.7.1/.gitignore000066400000000000000000000013501222645741400153400ustar00rootroot00000000000000*.o *.lo *.la *.out .deps/ .libs/ aclocal.m4 autom4te.cache/ build-aux/ m4/ !m4/ccalias.m4 !m4/iconv.m4 !m4/readline.m4 config.log config.status configure dumptypes.c dumptypes.h Makefile.in Makefile doc/*.1 INSTALL include/mdbver.h libmdb.pc libmdbsql.pc libtool mdbtools.spec types.h src/extras/mdb-hexdump src/gmdb2/gmdb2 src/gmdb2/help/C/omf_timestamp src/odbc/unittest src/sql/lexer.c src/sql/parser.c src/sql/parser.h src/util/mdb-array src/util/mdb-export src/util/mdb-header src/util/mdb-import src/util/mdb-parsecsv src/util/mdb-prop src/util/mdb-schema src/util/mdb-sql src/util/mdb-tables src/util/mdb-ver src/util/prcat src/util/prdata src/util/prdump src/util/prindex src/util/prkkd src/util/prole src/util/prtable src/util/updrow mdbtools-0.7.1/AUTHORS000066400000000000000000000017101222645741400144200ustar00rootroot00000000000000Brian Bruns Started MDB Tools Karl Nyberg Lots and lots of bug fixes and functionality Georg Bauer Lots and lots of bug fixes and functionality Carl Seutter Backend schema export, other stuff Trevor Harrison password field, etc... Brent Johnson large MEMO fields, deleted rows, double datatype Tim Nelson Multipage table defs, column totals > 255 David Mansfield Numerous patches Jeff Smith Patches too numerous to enumerate. Steve Langasek build fixes, ODBC fixes Rene Engelhard build fixes Vincent Fourmond float handling fix Tim Retout mdb-dump arg check fix, ODBC fix, add man pages Nirgal Vourgère postgres fixes and adds, bug fixes mdbtools-0.7.1/COPYING000066400000000000000000000432541222645741400144140ustar00rootroot00000000000000 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. mdbtools-0.7.1/COPYING.LIB000066400000000000000000000614471222645741400150250ustar00rootroot00000000000000 GNU LIBRARY GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 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. [This is the first released version of the library GPL. It is numbered 2 because it goes with version 2 of the ordinary GPL.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Library General Public License, applies to some specially designated Free Software Foundation software, and to any other libraries whose authors decide to use it. You can use it for your libraries, 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 library, or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link a program with the library, you must provide complete object files to the recipients so that they can relink them with the library, after making changes to the library and recompiling it. And you must show them these terms so they know their rights. Our method of protecting your rights has two steps: (1) copyright the library, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the library. Also, for each distributor's protection, we want to make certain that everyone understands that there is no warranty for this free library. If the library is modified by someone else and passed on, we want its recipients to know that what they have is not the original version, 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 companies distributing free software will individually obtain patent licenses, thus in effect transforming the program into proprietary software. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License, which was designed for utility programs. This license, the GNU Library General Public License, applies to certain designated libraries. This license is quite different from the ordinary one; be sure to read it in full, and don't assume that anything in it is the same as in the ordinary license. The reason we have a separate public license for some libraries is that they blur the distinction we usually make between modifying or adding to a program and simply using it. Linking a program with a library, without changing the library, is in some sense simply using the library, and is analogous to running a utility program or application program. However, in a textual and legal sense, the linked executable is a combined work, a derivative of the original library, and the ordinary General Public License treats it as such. Because of this blurred distinction, using the ordinary General Public License for libraries did not effectively promote software sharing, because most developers did not use the libraries. We concluded that weaker conditions might promote sharing better. However, unrestricted linking of non-free programs would deprive the users of those programs of all benefit from the free status of the libraries themselves. This Library General Public License is intended to permit developers of non-free programs to use free libraries, while preserving your freedom as a user of such programs to change the free libraries that are incorporated in them. (We have not seen how to achieve this as regards changes in header files, but we have achieved it as regards changes in the actual functions of the Library.) The hope is that this will lead to faster development of free libraries. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, while the latter only works together with the library. Note that it is possible for a library to be covered by the ordinary General Public License rather than by this special one. GNU LIBRARY GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Library General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, 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 library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete 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 distribute a copy of this License along with the Library. 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 Library or any portion of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, 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 Library, 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 Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you 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. If distribution of 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 satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also compile or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. c) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. d) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. 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. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library 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. 9. 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 Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library 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. 11. 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 Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library 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 Library. 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. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library 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. 13. The Free Software Foundation may publish revised and/or new versions of the Library 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 Library 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 Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, 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 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. 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 LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. 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 library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; 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. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! mdbtools-0.7.1/ChangeLog000066400000000000000000001104261222645741400151270ustar00rootroot00000000000000Tue May 23 19:40:55 CDT 2006 Jeff Smith * src/util/mdb-export.c: Fix typo in help text * configure.in: Clean up use of autoconf macros * src/gmdb2/util.c: Update call from Gtk+ 1.2 to 2.0 Sat Dec 17 03:49:30 CST 2005 Jeff Smith * src/util/mdb-sql.c: Add fflush after each newline (Pedro Gutierrez) * src/libmdb/table.c: Bugfix to read_pg_if_n (Mike Prudence) * src/libmdb/table.c: * src/libmdb/index.c: * include/mdbtools.h: Tidy up read_pg_in* functions Wed Nov 9 07:23:01 CST 2005 Jeff Smith * src/util/mdb-array.c: * src/util/mdb-header.c: * src/util/mdb-sql.c: * src/sql/parser.y: Fix several leaks and errors Fri Nov 4 06:10:41 CST 2005 Jeff Smith * src/libmdb/data.c: Fix in reading bound boolean fields (Yasir Assam) * src/libmdb/data.c: Several more fixes in reading data into bound fields Mon Oct 17 06:25:44 CDT 2005 Jeff Smith * src/util/mdb-prop.c: General cleanup * HACKING: Correct info about MDBICONV * include/mdbtools.h: * src/libmdb/backend.c: Make backend_name parameter a const char * * include/mdbsql.h: * src/sql/mdbsql.c: Make varaddr parameter a void * * src/libmdb/data.c: Use correct parameter in mdb_col_to_string * src/util/prole.c: Utilize mdb_bind_column_by_name Wed Sep 7 08:28:28 EDT 2005 Brian Bruns * src/util/mdb-export.c: Add -q and -X flags. Make -R and -d handle escaped characters properly * doc/mdb-export.txt: Update for new flags * src/util/mdb-export.c: Bug 1219521. Print error when table not found. * src/util/Makefile.am: move debugging programs to noinst * doc/faq.html: Update version number on expected write support. * doc/install.sgml: Add info about MDBICONV and MDB_JET3_CHARSET * src/util/mdb-sql.c: Fix -o option Tue Aug 30 21:24:46 EDT 2005 Brian Bruns * configure.in: add --disable-gmdb2 switch Tue Aug 9 23:36:01 CDT 2005 Jeff Smith * src/util/mdb-prop.c: Use correct index for command line options Fri Aug 5 10:49:57 CDT 2005 Jeff Smith * include/mdbtools.h: * src/libmdb/iconv.h: Use size_t instead of unsigned int for calling iconv Sat Jul 2 02:12:39 CDT 2005 Jeff Smith * include/mdbtools.h: * src/libmdb/data.c: * src/libmdb/dump.c: * src/libmdb/index.c: * src/libmdb/props.c: * src/libmdb/table.c: * src/libmdb/write.c: Alter buffer_dump's third parameter from 'end' to 'length' Mon Jun 27 23:52:15 CDT 2005 Jeff Smith * include/mdbtools.h: * src/gmdb2/debug.c: * src/libmdb/data.c: * src/libmdb/file.c: * src/libmdb/write.c: * src/util/prfreemap.c: * src/util/prindex.c: Use more appropriate types (void *, size_t) Thu Jun 23 00:40:32 CDT 2005 Jeff Smith * src/libmdb/write.c: Use col->is_fixed member directly * doc/reference/libmdb/libmdb-sections.txt: * include/mdbtools.h: * src/libmdb/file.c: * src/libmdb/index.c: * src/libmdb/write.c: Remove remaining int24 uses Sat Jun 18 01:49:03 CDT 2005 Jeff Smith * src/gmdb2/gladefiles/gmdb-debug.glade: * src/gmdb2/debug.c: Fix several lockups, leaks, and warnings Thu Jun 16 21:19:37 CDT 2005 Jeff Smith * src/libmdb/data.c: Fix segmentation fault * src/libmdb/write.c: Fix bug in handling certain 'jump tables' * src/util/mdb-schema.c: Handle 'file not found' case * src/libmdb/catalog.c: Fix some potential segmentation faults Mon May 2 07:28:58 CDT 2005 Jeff Smith * include/mdbtools.h: * src/libmdb/data.c: * src/libmdb/dump.c: * src/libmdb/file.c: * src/libmdb/iconv.c: * src/libmdb/index.c: * src/libmdb/table.c: * src/util/mdb-import.c: * src/util/prindex.c: * src/util/updrow.c: Clean up some gcc4 warnings Thu Apr 28 21:34:57 CDT 2005 Jeff Smith * src/util/mdb-check.c: * src/util/sargtest.c: Remove an unused variable and a noop * src/libmdb/backend.c: * src/libmdb/iconv.c: * src/libmdb/table.c: * src/odbc/unittest.c: Clean up some gcc4 warnings and errors Sat Apr 9 15:40:17 CDT 2005 Jeff Smith * src/gmdb2/gladefiles/gmdb-debug.glade: * src/gmdb2/gladefiles/gmdb-schema.glade: * src/gmdb2/gladefiles/gmdb-sql.glade: * src/gmdb2/gladefiles/gmdb.glade: Gladefile fixes (Edward Catmur) Fri Apr 8 20:36:51 CDT 2005 Jeff Smith * src/gmdb2/gladefiles/Makefile.am: * src/gmdb2/Makefile.am: Clean up minor gmdb makefile issues * include/mdbsql.h: Improve C++ compatibility (Horst Knorr) Wed Mar 30 23:21:25 CST 2005 Jeff Smith * autogen.sh: Improve order of autotools calls * config.cache: * install-sh: * missing: * mkinstalldirs: Remove files generated by autotools toolchain * .cvsignore: Ignore files generated by autotools toolchain Mon Mar 28 21:31:36 CST 2005 Jeff Smith * acinclude.m4: * src/util/Makefile.am: Only mdb-sql depends on readline * autogen.sh: * configure.in: Update some autotools macros Sun Mar 27 21:32:00 CST 2005 Jeff Smith * src/libmdb/file.c: Fix segfault on file-not-found Tue Mar 22 21:51:06 CST 2005 Jeff Smith * src/libmdb/data.c: Fix a bug in mdb_find_row Tue Mar 22 07:01:37 CST 2005 Jeff Smith * src/extras/mdb-dump.c: * src/libmdb/data.c: Clean up some warnings * src/libmdb/file.c: * src/libmdb/kkd.c: * src/libmdb/table.c: * src/libmdb/write.c: Replace a few mdb_pg_get_int's with mdb_get_int's Sat Mar 19 06:34:00 CST 2005 Jeff Smith * src/libmdb/Makefile.am: * src/libmdb/data.c: Clean up printing of floating-point values Wed Mar 16 06:41:57 CST 2005 Jeff Smith * include/mdbtools.h: * src/libmdb/data.c: Improve OLE-related functions * src/util/mdb-prop.c: Uncomment use of OLE functions * src/util/mdb-prop.c: Fix build error Sun Mar 13 15:22:11 CST 2005 Jeff Smith * src/util/mdb-export.c: * src/util/mdb-ver.c: Fix a couple of leaks * src/libmdb/data.c: * src/libmdb/sargs.c: * src/libmdb/write.c: * src/sql/mdbsql.c: Remove some unused variables Sat Mar 12 23:25:48 CST 2005 Jeff Smith * include/mdbtools.h: * src/libmdb/file.c: * src/libmdb/iconv.c: * src/libmdb/money.c: Changes for compiling in MSVC (Martin Ellis) Fri Mar 11 21:32:19 CST 2005 Jeff Smith * HACKING: * src/libmdb/data.c: * src/libmdb/iconv.c: Fix some issues with mdb_memo_to_string Sun Mar 6 22:09:09 CST 2005 Jeff Smith * src/libmdb/table.c: Fix memory leak * include/mdbtools.h: * src/libmdb/data.c: * src/libmdb/write.c: * src/util/prfreemap.c: * src/util/prindex.c: Add mdb_find_row function Fri Feb 25 23:02:42 CST 2005 Jeff Smith * src/libmdb/money.c: Fix bad declaration * src/libmdb/write.c: Rework of mdb_crack_row Thu Feb 24 21:13:02 CST 2005 Jeff Smith * src/libmdb/data.c: * src/libmdb/money.c: * src/libmdb/props.c: * src/odbc/odbc.c: Pass malloc'd strings with mdb_col_to_string, et al Fri Feb 11 10:41:55 EST 2005 Brian Bruns * src/libmdb/index.c: Fix off by one bug in mdb_index_swap_n() * src/libmdb/write.c: Fix bug in key hash * src/libmdb/mem.c: Comment out METHOD define(?) which broke compile * src/util/mdb-import.c: set fixed flag before calling pack_row Wed Feb 9 23:37:43 CST 2005 Jeff Smith * src/libmdb/data.c: Date calculation bugfix (David Mansfield) * src/libmdb/data.c: Deleted rows bugfix (David Mansfield) * src/libmdb/data.c: Convert memo fields (Artur Frysiak, me) Thu Feb 3 21:12:55 CST 2005 Jeff Smith * HACKING: Small documentation fix * src/gmdb2/debug.c: * src/gmdb2/gladefiles/gmdb-debug.glade: * src/gmdb2/gladefiles/gmdb.glade: Lots of gmdb2 updates and fixes Mon Jan 10 06:52:43 CST 2005 Jeff Smith * src/gmdb2/gladefiles/gmdb-debug.glade: * src/gmdb2/debug.c: * src/gmdb2/gmdb.h: * src/gmdb2/table.c: Modify functions to work better with Glade Wed Jan 5 07:43:07 CST 2005 Jeff Smith * src/gmdb2/debug.c: * src/gmdb2/file.c: * src/gmdb2/form.c: * src/gmdb2/gmdb.h: * src/gmdb2/macro.c: * src/gmdb2/main2.c: * src/gmdb2/module.c: * src/gmdb2/prefs.c: * src/gmdb2/query.c: * src/gmdb2/report.c: * src/gmdb2/schema.c: * src/gmdb2/sql.c: * src/gmdb2/table.c: * src/gmdb2/table_data.c: * src/gmdb2/table_def.c: * src/gmdb2/table_export.c: Fix various warnings Thu Dec 30 19:26:01 CST 2004 Jeff Smith * HACKING: * doc/reference/libmdb/libmdb-sections.txt: * include/mdbsql.h: * include/mdbtools.h: * src/gmdb/table_data.c: * src/gmdb/table_export.c: * src/gmdb2/sql.c: * src/gmdb2/table_data.c: * src/gmdb2/table_export.c: * src/libmdb/backend.c: * src/libmdb/catalog.c: * src/libmdb/data.c: * src/libmdb/file.c: * src/odbc/odbc.c: * src/sql/mdbsql.c: * src/util/mdb-array.c: * src/util/mdb-export.c: * src/util/mdb-prop.c: * src/util/prole.c: * src/util/sargtest.c: * src/util/updrow.c: Combine functions that bind a column and its length * src/gmdb/debug.c: * src/gmdb/table_def.c: * src/gmdb2/debug.c: * src/gmdb2/table_def.c: Replace malloc/memset with g_malloc0 * src/gmdb/debug.c: * src/gmdb/sql.c: * src/gmdb/table_data.c: * src/gmdb/table_export.c: * src/gmdb2/debug.c: * src/gmdb2/sql.c: * src/gmdb2/table_data.c: * src/gmdb2/table_export.c: Replace malloc/free with g_malloc/g_free Thu Dec 30 06:36:25 CST 2004 Jeff Smith * include/mdbtools.h: Fix MdbSargTreeFunc's typedef * src/sql/lexer.l: Fix flex warning about A-z ambiguity Tue Dec 28 21:25:24 CST 2004 Jeff Smith * src/libmdb/data.c: Handle dates from 1/1/100 to 12/31/9999 Sat Dec 11 00:03:17 CST 2004 Jeff Smith * HACKING: * include/mdbtools.h: * src/libmdb/data.c: * src/libmdb/iconv.c: * src/libmdb/index.c: * src/libmdb/sargs.c: * src/libmdb/table.c: * src/odbc/odbc.c: * src/sql/mdbsql.c: Better compressed text handling Wed Dec 1 18:18:02 EST 2004 Brian Bruns * src/libmdb/data.c: * src/libmdb/iconv.c: * src/libmdb/index.c: * src/libmdb/sargs.c: * src/libmdb/table.c: patch from Wind Li for iconv on jet3 * src/libmdb/write.c: write out leaf page with added index entry, not quite working yet (bitmap not written correctly and key hash value wrong) but closer. * src/util/mdb-import.c: temporary kludge for problems caused by using g_strsplit() and friends Wed Dec 1 00:33:38 CST 2004 Jeff Smith * src/libmdb/table.c: * src/libmdb/iconv.c: * src/util/mdb-sql.c: Clean up some memory leaks Sat Nov 27 12:16:08 CST 2004 Jeff Smith * src/odbc/odbc.c: Update ascii2unicode conversion calls Fri Nov 26 00:10:58 EST 2004 Brian Bruns * include/mdbtools.h: * src/gmdb2/table_def.c: * src/gmdb2/gladefiles/gmdb-schema.glade: * src/libmdb/data.c: * src/libmdb/file.c: * src/libmdb/iconv.c: * src/libmdb/index.c: * src/libmdb/options.c: * src/libmdb/sargs.c: * src/libmdb/table.c: * src/sql/mdbsql.c: iconv conversion Sat Nov 13 20:33:42 EST 2004 Brian Bruns * src/gmdb2/gmdb.h: remove redeclaration errors * src/gmdb2/sql.c: fix compiler warnings * src/gmdb2/debug.c: * src/gmdb2/file.c: * src/gmdb2/schema.c: * src/gmdb2/sql.c: * src/gmdb2/table_export.c: patch #1038578 from Filip Van Raemdonck * src/sql/mdbsql.c: * include/mdbsql.h: patch #1034566 from Filip Van Raemdonck * src/odbc/Makefile.am: patch #1030353 from Filip Van Raemdonck Wed Oct 27 22:32:33 CDT 2004 Jeff Smith * src/util/mdb-sql.c: Various mdb-sql improvements Sun Oct 24 23:07:16 CDT 2004 Jeff Smith * configure.in: * src/gmdb2/Makefile.am: * src/libmdb/Makefile.am: * src/util/Makefile.am: * src/util/mdb-sql.c: Readline usage fixes * src/sql/Makefile.am: * src/sql/main.c: Remove obsolete file Wed Oct 20 21:49:04 CDT 2004 Jeff Smith * src/sql/mdbsql.c: Get rid of GLib 2.4+ call Sat Oct 16 09:19:16 CDT 2004 Jeff Smith * INSTALL: * README: * configure.in: * include/mdbodbc.h: * src/odbc/connectparams.c: * src/odbc/odbc.c: Get ODBC driver to work for iODBC Fri Sep 24 00:07:10 CDT 2004 Jeff Smith * doc/install.sgml: Document odbcinst.ini entry Thu Sep 23 00:04:05 CDT 2004 Jeff Smith * src/libmdb/money.c: * src/libmdb/data.c: * src/sql/mdbsql.c: * src/odbc/odbc.c: Correct some field display size problems Tue Sep 21 22:03:56 CDT 2004 Jeff Smith * HACKING: Numerous corrections and readability improvements * src/odbc/odbc.c: Return SQL_NO_DATA for SQLMoreResults Wed Sep 15 22:59:26 CDT 2004 Jeff Smith * include/mdbtools.h: * src/gmdb/sql.c: * src/gmdb/table.c: * src/gmdb2/schema.c: * src/gmdb2/sql.c: * src/gmdb2/table.c: * src/libmdb/catalog.c: * src/libmdb/table.c: * src/odbc/odbc.c: * src/sql/mdbsql.c: * src/util/mdb-check.c: * src/util/mdb-header.c: * src/util/mdb-schema.c: * src/util/mdb-tables.c: * HACKING: Use 'Flags' field in MSysObjects to recognize system tables * TODO: Update TODO to reflect status of multipage work tables Wed Sep 15 07:33:34 CDT 2004 Jeff Smith * src/odbc/Makefile.am: Fix a bug in ODBC Makefile Mon Sep 13 19:10:24 CDT 2004 Jeff Smith * src/odbc/odbc.c: Fix a bug in SQLConnect Sun Sep 12 14:03:10 CDT 2004 Jeff Smith * include/mdbtools.h: * src/libmdb/write.c: * src/libmdb/worktable.c: Temp table improvements * src/odbc/odbc.c: Implement SQLTables and SQLColumns Wed Sep 8 22:24:29 CDT 2004 Jeff Smith * HACKING: Small format documentation correction * include/mdbtools.h: * src/libmdb/data.c: * src/libmdb/table.c: * src/libmdb/worktable.c: * src/libmdb/write.c: * src/odbc/odbc.c: * src/sql/mdbsql.c: * src/util/mdb-sql.c: Enable multi-page temp tables Wed Sep 8 07:37:08 CDT 2004 Jeff Smith * include/mdbtools.h: * src/libmdb/data.c: * src/libmdb/table.c: Add function mdb_find_pg_row Thu Sep 2 23:04:02 CDT 2004 Jeff Smith * doc/reference/libmdb/libmdb-sections.txt: * include/mdbtools.h: * src/libmdb/catalog.c: Remove function mdb_alloc_catalog Sat Aug 28 14:21:41 CDT 2004 Jeff Smith * src/libmdb/data.c: Fix mdb_read_next_dpg Correct long int display length * src/libmdb/data.c: * src/libmdb/map.c: Fix a bug in reading usage maps Sat Aug 28 00:20:44 CDT 2004 Jeff Smith * src/libmdb/write.c: Jump table packing/cracking improvements * src/libmdb/worktable.c: Fix bug in temp tables with multiple columns * src/libmdb/data.c: Minor simplification in mdb_read_row Thu Aug 26 21:06:35 CDT 2004 Jeff Smith * src/libmdb/write.c: Documentation fix * src/sql/lexer.l: Add SQL quote escaping * src/libmdb/worktable.c: Fix bug in creating temp tables * src/libmdb/write.c: mdb_crack_row3 rewrite Tue Aug 24 21:04:17 CDT 2004 Jeff Smith * include/mdbsql.h: * src/sql/mdbsql.c: Tidy up a few SQL-related functions * src/libmdb/iconv.c: Tighten packing of strings into rows * src/libmdb/write.c: Fix bug in storing variable-length field offsets Sat Aug 21 21:21:56 CDT 2004 Jeff Smith * src/libmdb/file.c: Clean up a bug in the new mdb_get_single/double * src/libmdb/data.c: Clean out some stale code * src/sql/parser.y: Simplify a couple of rules Thu Aug 19 21:37:21 CDT 2004 Jeff Smith * configure.in: * src/libmdb/file.c: Use GLib to deal with endian issues Thu Aug 19 07:50:56 CDT 2004 Jeff Smith * src/libmdb/data.c: * src/libmdb/map.c: Factorizing usage map functions Wed Aug 18 23:31:34 CDT 2004 Jeff Smith * doc/reference/libmdb/libmdb-sections.txt: * include/mdbtools.h: * src/libmdb/file.c: * src/libmdb/stats.c: Tidy up stats interface Tue Aug 17 22:46:13 CDT 2004 Jeff Smith * src/libmdb/data.c: Fix and simplify usage map handling * HACKING: Minor documentation corrections Wed Aug 4 21:22:46 CDT 2004 Jeff Smith * HACKING: * include/mdbtools.h: * src/libmdb/write.c: * src/libmdb/table.c: A fix for bug #669739 that became a mdb_crack_row4 rewrite. Thanks to Luciano Miguel Wolf and Alexandre Horst for the bug analysis and the initial patch. Sat Jul 17 23:09:40 CDT 2004 Jeff Smith * src/libmdb/catalog.c: Clean out some stale code * src/libmdb/data.c: Use mdb_unicode2ascii in mdb_col_to_string * src/libmdb/data.c: Clean out some stale code Sat Jul 17 09:21:13 CDT 2004 Jeff Smith * include/mdbtools.h: * src/libmdb/index.c: * src/libmdb/write.c: * src/util/prindex.c: Warnings fixes * src/libmdb/map.c: Warnings fixes Sat Jul 17 02:47:16 CDT 2004 Jeff Smith * include/mdbtools.h: * src/libmdb/data.c: * src/libmdb/kkd.c: * src/libmdb/like.c: * src/libmdb/table.c: * src/libmdb/write.c: * src/util/mdb-import.c: Warnings fixes and better use of GLib Fri Jul 9 07:47:27 CDT 2004 Jeff Smith * include/mdbsql.h: * include/mdbtools.h: * src/extras/mdbsupport.c: * src/libmdb/catalog.c: * src/libmdb/data.c: * src/libmdb/file.c: * src/libmdb/index.c: * src/libmdb/sargs.c: * src/libmdb/table.c: * src/libmdb/write.c: * src/sql/mdbsql.c: * src/util/mdb-array.c: * src/util/mdb-export.c: * src/util/mdb-header.c: * src/util/mdb-import.c: * src/util/mdb-schema.c: * src/util/mdb-sql.c: * src/util/mdb-tables.c: * src/util/prindex.c: * src/util/prole.c: * src/util/prtable.c: * src/util/updrow.c: Lots more gcc warnings fixes Fri Jul 2 23:52:34 CDT 2004 Jeff Smith * src/libmdb/backend.c: * src/libmdb/iconv.c: * src/libmdb/index.c: * include/mdbtools.h: Fixes based on 'gcc -W -Wall' warnings * src/libmdb/file.c: * src/libmdb/write.c: * include/mdbtools.h: Replace size_t with ssize_t as appropriate Fri Jul 2 07:27:32 CDT 2004 Jeff Smith * src/libmdb/backend.c: * src/libmdb/table.c: * src/sql/mdbsql.c: * src/util/mdb-array.c: * src/util/mdb-export.c: * src/util/mdb-import.c: * src/util/mdb-prop.c: * src/util/prdata.c: * src/util/prindex.c: * src/util/prole.c: * src/util/sargtest.c: * src/util/updrow.c: * include/mdbtools.h: Add function mdb_read_table_by_name Wed Jun 23 23:19:43 CDT 2004 Jeff Smith * src/libmdb/table.c: * src/util/mdb-array.c: * src/util/mdb-check.c: * src/util/mdb-header.c: * src/util/mdb-import.c: * src/util/mdb-prop.c: * src/util/prdata.c: * src/util/prindex.c: * src/util/prole.c: * src/util/sargtest.c: * src/util/updrow.c: Fix some memory leaks * include/mdbtools.h: Remove duplicate declaration Wed Jun 23 07:30:17 CDT 2004 Jeff Smith * src/libmdb/table.c: * src/libmdb/mem.c * include/mdbtools.h: Move table and column functions to table.c * src/libmdb/stats.c: * src/libmdb/mem.c * include/mdbtools.h: Move statistics functions to stats.c Tue Jun 22 22:02:02 CDT 2004 Jeff Smith * src/util/mdb-schema.c: Fix a memory leak * src/libmdb/mem.c: Fix another memory leak * src/libmdb/catalog.c: Bind columns by name in mdb_read_catalog * src/libmdb/worktable.c: Remove only use of mdb_append_column * src/libmdb/catalog.c: * src/libmdb/mem.c: * include/mdbtools.h: Move catalog functions to catalog.c Mon Jun 21 23:18:18 CDT 2004 Jeff Smith * src/libmdb/backend.c: * src/libmdb/file.c: * src/libmdb/like.c: * src/libmdb/money.c: Add gtkdoc to various functions Sun Jun 20 09:37:58 EDT 2004 Brian Bruns * configure.in: * acinclude.m4: use READLINE macro from Ville Laurikari. Remove full macroset to work around broken BSD autoconf. Add macro for iconv detection. * src/util/mdb-sql.c: add stubs for read_history/write_history if no readline. update to use new readline defines. * HACKING: reverse order of total column count with current column count. * README: fix typo * include/mdbtools.h: add iconv handle to MdbHandle * src/libmdb/file.c: add gtkdoc to mdb_find_file() * src/libmdb/Makefile.am: * src/sql/Makefile.am: add libtool versioning * src/gmdb2/gladefiles/gmdb-schema.glade: * src/gmdb2/schema.c: Add MySQL to export * src/gmdb2/help/C/gmdb.xml: fix typo Fri Jun 18 00:08:24 CDT 2004 Jeff Smith * HACKING: * src/libmdb/index.c: * src/libmdb/mem.c: * include/mdbtools.h: Reconcile code/documentation inconsistencies * src/util/mdb-schema.c: Fix a bug and a typo in mdb-schema * src/libmdb/index.c: Replace a function with an equivalent GLib macro Thu Jun 17 20:56:44 EDT 2004 Brian Bruns * configure.in: temporarily remove building of reference manual. It broke 'make dist' Wed Jun 16 17:35:07 EDT 2004 Brian Bruns * src/gmdb2/file.c: initialize default backend * src/gmdb2/table_def.c: replace reference to mdb_access_types structure with call to mdb_get_coltype_string() * include/mdbtools.h: increase max objects to 256 bytes. Mon Jun 14 22:52:00 CDT 2004 Jeff Smith * src/libmdb/table.c: Fix bug in column name ordering Mon Jun 14 07:12:37 CDT 2004 Jeff Smith * src/libmdb/table.c: Make better use of read_pg_if_n Fri Jun 11 16:56:06 CDT 200 Jeff Smith * src/libmdb/table.c: Fix bug in read_pg_if_n Fri Jun 11 08:52:14 CDT 2004 Jeff Smith * src/libmdb/data.c: * src/libmdb/backend.c: * src/gmdb2/schema.c: * src/util/mdb-schema.c: * include/mdbtools.h: Major revisions to 'backend' code Wed Jun 2 07:31:04 CDT 2004 Jeff Smith * src/libmdb/file.c: Improve mdb_open's error handling Mon May 31 12:19:05 CDT 2004 Jeff Smith * src/libmdb/file.c: Make better use of glib functions Sun May 30 00:04:55 CDT 2004 Jeff Smith * src/libmdb/data.c: * src/libmdb/file.c: * src/libmdb/mem.c: * src/libmdb/table.c: malloc to g_malloc * src/sql/main.c: * src/sql/mdbsql.c: better utilize glib functions, fix memory leak * src/util/mdb-array.c: * src/util/mdb-check.c: * src/util/mdb-export.c: * src/util/mdb-import.c: * src/util/mdb-schema.c: * src/util/mdb-sql.c: * src/util/mdb-tables.c: * src/util/sargtest.c: better utilize glib functions, fix memory leaks * src/odbc/connectparams.c: * src/odbc/odbc.c: better utilize glib functions, fix memory leak Sat May 29 14:14:21 CDT 2004 Jeff Smith * src/libmdb/backend.c: * src/libmdb/file.c: malloc to g_malloc for backend functions Fri May 28 06:55:55 CDT 2004 Jeff Smith * src/libmdb/mem.c: Fixed a couple of potential memory leaks * include/mdbtools.h: Fixed a couple of compiler warnings Sun May 2 06:31:17 EDT 2004 Brian Bruns * src/util/mdb-tables.c: Add -t flag to specify object type * src/util/mdb-props.c: Handle any object type, not just tables Sat May 1 00:02:09 CDT 2004 Jeff Smith * doc/reference/libmdb/libmdb-sections.txt: * include/mdbtools.h: * src/libmdb/file.c: * src/libmdb/mem.c: * src/libmdb/stats.c: Fold several functions into mdb_open/mdb_close * doc/reference/libmdb/.cvsignore: Added this file 2004-04-29 Michael Meeks * configure.in * Makefile.am: add mdbtools pkgconfig bits * libmdb.pc.in * libmdbsql.pc.in: add mdbtools pkgconfig templates. Sat Apr 24 21:39:10 CDT 2004 Jeff Smith * src/libmdb/file.c: * src/libmdb/mem.c: Moving some NULL pointer tests * src/libmdb/mem.c * src/libmdb/props.c: * src/sql/mdbsql.c: Back out some ineffective NULL setting Sat Apr 24 15:27:51 CDT 2004 Jeff Smith * src/libmdb/file.c: * src/libmdb/props.c * src/sql/mdbsql.c: Setting pointers to NULL after freeing Sat Apr 24 00:02:14 CDT 2004 Jeff Smith * src/libmdb/mem.c: * src/libmdb/catalog.c: Setting various pointers to NULL after freeing. * src/libmdb/mem.c: * src/libmdb/file.c: Cleaning up memory for catalogs Fri Apr 16 10:48:05 EDT 2004 Brian Bruns * src/libmdb/write.c: restructuring of mdb_crack_row?() to accomodate columns deletes/adds * src/libmdb/index.c: fix stupid bug in mdb_swap_n() Tue Apr 13 19:08:51 CDT 2004 Jeff Smith * src/util/mdb-check.c: Make mdb-check compilable * configure.in: * src/odbc/Makefile.am: Improve configure for ODBC * acinclude.m4: Update to the latest libtool.m4 * src/libmdb/file.c: Make mdb_close free the handle * src/sql/mdbsql.c: * src/util/mdb-array.c: * src/util/mdb-check.c: * src/util/mdb-export.c: * src/util/mdb-header.c: * src/util/mdb-import.c: * src/util/mdb-prop.c: * src/util/mdb-schema.c: * src/util/mdb-tables.c: * src/util/mdb-ver.c: * src/util/prcat.c: * src/util/prdata.c: * src/util/prdump.c: * src/util/prfreemap.c: * src/util/prindex.c: * src/util/prkkd.c: * src/util/prole.c: * src/util/prtable.c: * src/util/sargtest.c: * src/util/updrow.c: Use mdb_close to match mdb_open instead of mdb_free_handle Tue Apr 13 15:25:26 EDT 2004 Brian Bruns * include/mdbtools.h: * src/sql/mdbsql.c: * src/util/mdb-array.c: * src/util/mdb-check.c: * src/util/mdb-export.c: * src/util/mdb-header.c: * src/util/mdb-import.c: * src/util/mdb-prop.c: * src/util/mdb-schema.c: * src/util/mdb-tables.c: * src/util/mdb-ver.c: * src/util/prcat.c: * src/util/prdata.c: * src/util/prdump.c: * src/util/prfreemap.c: * src/util/prindex.c: * src/util/prkkd.c: * src/util/prole.c: * src/util/prtable.c: * src/util/sargtest.c: * src/util/updrow.c: * src/gmdb/file.c: * src/gmdb2/file.c: * src/libmdb/file.c: Add flags argument to mdb_open to support read/write files * doc/reference/libmdb/libmdb-sections.txt: Organize reference manual a little better Mon Apr 12 21:58:00 CDT 2004 Jeff Smith * src/odbc/connectparams.c: ODBC driver dialog enhancements * src/sql/mdbsql.c: Correct some array sizes * src/odb/odbc.c: Utilize _odbc_get_string_size() in SQLPrepare() * src/libmdb/mem.c: Make mdb_free_tabledef safe from dereferencing NULL Mon Apr 12 09:56:23 EDT 2004 Brian Bruns * include/mdbtools: * src/libmdb/mem.c: * src/libmdb/backend.c: free backends on exit (Jeff Smith) * src/libmdb/index.c: missing function mdb_swap_n() * src/libmdb/file.c: * src/libmdb/mem.c: * src/libmdb/stats.c: * configure.in: * doc/reference/libmdb/Makefile.am: * doc/reference/libmdb/libmdb-sections.txt: * doc/reference/libmdb/libmdb-docs.sgml: Initial cut at gtk-doc reference manual * include/mdbtools.h: Change MdbSargNode typedef to forward declaration to make gtk-doc happy * doc/faq.html: Fix unclosed
    tag * TODO: update finished items Thu Mar 25 04:56:05 EST 2004 Brian Bruns * src/odbc/odbc.c(_SQLFreeStmt): call mdb_sql_reset on stmt drop (Jeff Smith) Sat Mar 13 09:27:23 EST 2004 Brian Bruns * doc/faq.html: fix typos, add question on write support * doc/install.sgml: clarify yacc requirement * doc/mdb-ver.txt: add -M to options * doc/mdb-sql.txt: add BUGS sections * src/libmdb/data.c: fix bug in call to mdb_get_double (Jeff Smith) * src/libmdb/write.c: move declaration to top of function in crack_row3 (Jeff Smith), check for null in mdb_pack_row[3-4] (me) * src/libmdb/index.c: fix hard coded index size in compressed index handling * src/sql/lexer.l: missing ] in NUMBER (Jeff Smith) * src/sql/mdbsql.c: temp_fill called with wrong value (Jeff Smith) * src/odbc/odbc.c: fix typo, incorrect pointer dereference (Jeff Smith), change value to SQLSMALLINT * in type_info Sat Mar 6 18:10:20 EST 2004 Brian Bruns * include/mdbsql.h: * src/libmdb/worktable.c: * src/sql/mdbsql.c: introduced convience functions for building temp tables * src/libmdb/write.c: remove dead statement * src/libmdb/iconv.c: check for null string in mdb_ascii2unicode * src/odbc/odbc.c: implement SQLGetTypeInfo bug #903498 Fri Mar 5 23:24:04 EST 2004 Brian Bruns * configure.in: AC_SUBST on ODBCINSTLIB * include/mdbtools.h: * src/libmdb/Makefile.am: * src/odbc/Makefile.am: * src/libmdb/data.c: * src/libmdb/iconv.c: move ascii/unicode convert code to iconv.c * include/mdbsql.h: * src/util/mdb-sql.c: * src/odbc/odbc.c: * src/sql/mdbsql.c: new fetch routine to handle worktables * src/odbc/connectparams.c: use odbcinst lib routines if available Thu Mar 4 23:24:27 EST 2004 Brian Bruns * include/mdbtools.h: add prototype for mdb_index_find_next() * src/libmdb/write.c: add mdb_pack_row4() (Jeff Smith). Fix null mask order (Jeff, me) * src/sql/mdbsql.c: convert list tables/describe table to ucs2 for jet4 db's Thu Mar 4 15:30:21 EST 2004 Brian Bruns * src/odbc/Makefile.am: add newer files to driver * src/libmdb/options.c: add debug_row option * src/libmdb/data.c: loop for num_cols (current columns definition) not num_fields (columns on row) * src/libmdb/write.c: read deleted fixed columns correctly under jet4 * include/mdbtools.h: * src/libmdb/file.c: * src/libmdb/table.c: store fixed and variable offsets and postions from tdef in column structure. * include/mdbodbc.h: * src/odbc/connectparams.c: Add ODBCINSTGetProperties function for setup lib. * configure.in: Add detection of SQLGetPrivateProfileString * README: clarify LGPL covered files * INSTALL: clarify yacc/bison Sun Feb 15 07:37:19 EST 2004 Brian Bruns * HACKING: better description of Jet4 column deletion/addition * src/gmdb2/gladefiles/gmdb-debug.glade: remove incorrect default callback * src/gmdb2/debug.c: move declarations to top of function, fixes bug 675022 fix -Wall messages add data page dissector for jet4 * src/libmdb/data.c: merge patch for bug #688655, check negative values on datetime * src/libmdb/money.c: increase MAXPRECISION to 20 * src/libmdb/options.c: new file * src/libmdb/table.c: * src/libmdb/data.c: * src/libmdb/write.c: * src/libmdb/like.c: * src/libmdb/index.c: convert to use mdb_get_option/mdb_debug Sat Feb 14 14:41:00 EST 2004 Brian Bruns * include/.cvsignore: add mdbver.h * include/mdbtools: remove variables for old index algorithm. * src/libmdb/index.c: missing return in mdb_index_find_next, remove old index algorithm. Add mdb_index_pack_bitmap() function and rename unpack routine to match. * src/libmdb/write.c: port fix from data.c to mdb_crack_row() routines * src/gmdb2/debug.c: more tdef4 dissector work * HACKING: column deletion revelation/thoughts. Fri Feb 13 12:51:50 EST 2004 Brian Bruns * src/extras/.cvsignore: change mdb-dump to mdb-hexdump * include/Makefile.am: * include/mdbver.h.in: new file * configure.in: add mdbver.h to AC_OUTPUT * src/util/mdb-ver.c: add -M flag to show MDB Tools version to help support * src/gmdb2/main2.c: change version number to mdbtools version number * src/gmdb2/sql.c: added some (commented) code to change cursor on execute. * src/gmdb2/table.c: right mouse click selects before calling popup. * src/gmdb2/debug.c: add separate dissector for jet4 tdef pages * src/gmdb2/gladefiles/gmdb2-prefs.glade: add help button * src/libmdb/index.c: pre-compute index page bitmap in mdb_index_unpack_page() in preparation for index writes. * include/mdbtools.h: change IndexPage structure for new algorithm Wed Feb 11 15:30:42 EST 2004 Brian Bruns * HACKING: rewritten to better reflect Jet4 * src/gmdb2/gmdb2.h: add prototype for gmdb_debug_set_dissect_cb() * src/gmdb2/debug.c: add switch to control dissecting pages or no * src/gmdb2/gladefiles/gmdb-debug.glade: add dissect option to View menu * src/libmdb/data.c: adding debugging code * src/libmdb/table.c: adding debugging code for usage maps * src/libmdb/write.c: remove jet3 check from mdb_crack_row4() * include/mdbtools.h: * src/libmdb/index.c: handle compressed indexes, trailing leaves Mon Feb 9 14:53:19 EST 2004 Brian Bruns * src/util/mdb-export.c: reorganized a bit, added header text and options from patch #857342 * src/util/mdb-export.c: added -I option from patch #857342 * src/gmdb2/gladefiles/gmdb-schema.glade: fix close button * src/sql/lexer.l: allow negative numbers Sun Feb 8 13:02:56 EST 2004 Brian Bruns * doc/faq.html: update email addy * doc/userguide.sgml: fix typo * src/libmdb/backend.c: mysql patch * src/odbc/odbc.c: * src/util/mdb-sql.c: * src/gmdb2/sql.c: change mdbsql_bind_col to mdb_sql_bind_col to match other functions * include/mdbtools.h: move mdb_backends to .c file * src/sql/lexer.l: fix STRING token from overreading * include/mdbsql.h: * src/sql/parser.y: * src/sql/mdbsql.c: added mdb_sql_eval_expr() to support 0=1 literal comparison * src/libmdb/sargs.c: check for null node->col (literal comparision) * src/sql/Makefile.am: change hardcoded bison reference to @YACC@ Fri Feb 6 18:08:59 EST 2004 Brian Bruns * include/mdbtools.h: * src/sql/mdbsql.c: * src/libmdb/sargs.c: change signature of mdb_test_sarg to test for nulls * src/mdbsql/lexer.l: add NULL token * src/libmdb/data.c: memo patch from * src/libmdb/file.c: patch #889589 * src/libmdb/write.c: patch #889586 Thu Feb 5 20:45:00 EST 2004 Brian Bruns * HACKING: added information on indexes * src/sql/lexer.l: * src/sql/parser.y: added is null/is not null, not working yet * src/util/mdb-sql.c: fix readline support, added history file * src/util/mdb-export.c: update usage for -D flag * src/libmdb/backend.c: added mysql struct (not complete) * src/libmdb/sargs.c: fix casts * src/libmdb/write.c: break apart mdb_crack_row new index func Sat Jan 10 17:18:00 EST 2004 Brian Bruns * src/util/mdb-parse.c: fixed char comparison to -1 re: bug 688181 Fri Jan 9 15:22:11 EST 2004 Brian Bruns * include/mdbtools.h: * src/libmdb/index.c: * src/libmdb/write.c: modularize this a bit more to allow reuse * src/libmdb/worktable.c: preliminary worktable/temp table support * src/libmdb/table.c: fix reading of free page map and enable * src/data/data.c: use mdb_crack_row() from write.c for cleaner row handling. Fix delflag bug. * src/util/updrow.c: fix sarg handling * src/util/mdb-import.c: check for valid table * src/sql/mdbsql.c: * src/util/mdb-sql.c: Fix H and F flags. Change "list tables" and "describe table" to write to worktable so client can pull results (almost) like a normal query. Wed Jan 22 14:54:11 EST 2003 Brian Bruns * src/util/mdb-sql.c: typo fix * src/gmdb2/gladefiles/gmdb-debug.glade: * src/gmdb2/gladefiles/gmdb-sql.glade: * src/gmdb2/gladefiles/gmdb.glade: toolbar separator fix (glade/libglade buglet) Tue Jan 21 18:10:46 EST 2003 Brian Bruns * src/libmdb/data.c: move unicode to ascii code to mdb_unicode2ascii function * src/libmdb/sarg.c: add MdbHandle argument to mdb_sarg_test and invoke mdb_unicode2ascii * src/libmdb/like.c: added debugging info * include/mdbtools.h: prototypes * src/sql/mdbsql.c: fix case compare bug in where clause Tue Apr 2 21:02:13 EST 2002 Brian Bruns * src/libmdb/data.c: ignore 0xff in row offset table (Don Badrak) Wed Mar 20 22:49:33 EST 2002 Brian Bruns * include/mdbtools.h: increased page size from 2048 to 4096 Sat Mar 16 21:37:01 EST 2002 Brian Bruns * include/mdbtools.h: added oam usage map fields to TableDef * src/extras/mdb-dump.c: added JET4 support * src/libmdb/data.c: added code to check for unicode compression * src/libmdb/mem.c(mdb_free_tabledef): clean up for oam fields 2002-03-15 Brian Bruns * src/libmdb/money.c: Two's complement fix from * src/libmdb/data.c: BOOL fixes from Mike Finger and Ben McKeegan * src/libmdb/table.c: BOOL fixes from Mike Finger 2001-09-29 Brian Bruns * src/odbc/odbc.c: Added implementation of SQLNumResultCols() * src/sql/lexer.l: Added yywrap function, so ODBC driver may be linked without libfl * src/util/mdb-sql.c src/sql/parser.y src/odbc/odbc.c: Added mdb_sql_set() function so mdb-sql and ODBC driver do not need to set g_sql directly. 2001-09-28 Brian Bruns * src/odbc/unittest.c: Changed dwNativeError vars to SQLINTEGER to fix compile warning * src/util/mdb-sql.c src/sql/mdbsql.c: Check for cur_table before calling mdb_dump_results() Make mdb_sql_reset() dealloc and clear cur_table mdbtools-0.7.1/HACKING000066400000000000000000001345731222645741400143550ustar00rootroot00000000000000This file documents the Microsoft MDB file format for Jet3 and Jet4 databases. General Notes ------------- Access (Jet) does not in general initialize pages to zero before writing them, so the file will contains a lot of unititialized data. This makes the task of figuring out the format a bit more difficult than it otherwise would be. This document will, generally speaking, provide all offsets and constants in hex format. Most multibyte pointer and integers are stored in little endian (LSB-MSB) order. There is an exception in the case of indexes, see the section on index pages for details. Terminology ----------- This section contains a mix of information about data structures used in the MDB file format along with general database terminology needed to explain these structures. Page - A fixed size region within the file on a 2 or 4K boundry. All data in the file exists inside pages. System Table - Tables in Access generally starting with "MSys". The 'Flags' field in the table's Catalog Entry will contain a flag in one of two positions (0x80000000 or 0x00000002). See also the TDEF (table definition) pages for "System Table" field. Catalog Entry - A row from the MSysObjects table describing another database object. The MSysObjects table definition page is always at page 2 of the database, and a phony tdef structure is bootstrapped to initially read the database. Page Split - A process in which a row is added to a page with no space left. A second page is allocated and rows on the original page are split between the two pages and then indexes are updated. Pages can use a variety of algorithms for splitting the rows, the most popular being a 50/50 split in which rows are divided evenly between pages. Overflow Page - Instead of doing a full page split with associated index writes, a pointer to an "overflow" page can be stored at the original row's location. Compacting a database would normally rewrite overflow pages back into regular pages. Leaf Page - The lowest page on an index tree. In Access, leaf pages are of a different type than other index pages. UCS-2 - a two byte unicode encoding used in Jet4 files. Covered Query - a query that can be satisfied by reading only index pages. For instance if the query "SELECT count(*) from Table1 where Column3 = 4" were run and Column3 was indexed, the query could be satisfied by reading only indexes. Because of the way Access hashes text columns in indexes, covered queries on text columns are not possible. Pages ----- At its topmost level, a MDB file is organized into a series of fixed-size pages. These are 2K in size for Jet3 (Access 97) and 4K for Jet4 (Access 2000/2002). All data in MDB files exists within pages, of which there are a number of types. The first byte of each page identifies the page type as follows. 0x00 Database definition page. (Always page 0) 0x01 Data page 0x02 Table definition 0x03 Intermediate Index pages 0x04 Leaf Index pages 0x05 Page Usage Bitmaps (extended page usage) 0x08 ?? Database Definition Page ------------------------ Each MDB database has a single definition page located at beginning of the file. Not a lot is known about this page, and it is one of the least documented page types. However, it contains things like Jet version, encryption keys, and name of the creating program. Note, this page is "encrypted" with a simple rc4 key starting at offset 0x18 and extending for 126 (Jet3) or 128 (Jet4) bytes. Offset 0x14 contains the Jet version of this database: 0x00 for 3, 0x01 for 4, 0x02 for 5, 0x03 for Access 2010. This is used by the mdb-ver utility to determine the Jet version. The 20 bytes (Jet3) or 40 bytes (Jet4) starting at 0x42 are the database password. In Jet4, there is an additional mask applied to this password derived from the database creation date (also stored on this page as 8 bytes starting at offset 0x72). The 4 bytes at 0x3e on the Database Definition Page are the database key. The 2 bytes at 0x3C are the default database code page (useless in Jet4?). The 2 bytes at 0x3A (Jet3) or 4 bytes at 0x6E (Jet4) are the default text collating sort order. Data Pages ---------- Data rows are all stored in data pages. The header of a Jet3 data page looks like this: +--------------------------------------------------------------------------+ | Jet3 Data Page Definition | +------+---------+---------------------------------------------------------+ | data | length | name | description | +------+---------+---------------------------------------------------------+ | 0x01 | 1 byte | page_type | 0x01 indicates a data page. | | 0x01 | 1 byte | unknown | | | ???? | 2 bytes | free_space | Free space in this page | | ???? | 4 bytes | tdef_pg | Page pointer to table definition | | ???? | 2 bytes | num_rows | number of records on this page | +--------------------------------------------------------------------------+ | Iterate for the number of records | +--------------------------------------------------------------------------+ | ???? | 2 bytes | offset_row | The record's location on this page | +--------------------------------------------------------------------------+ Notes: . In Jet4, an additional four-byte field was added after tdef_pg. Its purpose is currently unknown. . Offsets that have 0x40 in the high order byte point to a location within the page where a Data Pointer (4 bytes) to another data page (also known as an overflow page) is stored. Called 'lookupflag' in source code. . Offsets that have 0x80 in the high order byte are deleted rows. Called 'delflag' in source code. Rows are stored from the end of the page to the top of the page. So, the first row stored runs from the row's offset to page_size - 1. The next row runs from its offset to the previous row's offset - 1, and so on. Decoding a row requires knowing the number and types of columns from its TDEF page. Decoding is handled by the routine mdb_crack_row(). +--------------------------------------------------------------------------+ | Jet3 Row Definition | +------+---------+---------------------------------------------------------+ | data | length | name | description | +------+---------+---------------------------------------------------------+ | ???? | 1 byte | num_cols | Number of columns stored on this row. | | ???? | n bytes | fixed_cols | Fixed length columns | | ???? | n bytes | var_cols | Variable length columns | | ???? | 1 byte | eod | length of data from begining of record | | ???? | n bytes | var_table[]| offset from start of row for each var_col | | ???? | n bytes | jump_table | Jump table (see description below) | | ???? | 1 byte | var_len | number of variable length columns | | ???? | n bytes | null_mask | Null indicator. See notes. | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ | Jet4 Row Definition | +------+---------+---------------------------------------------------------+ | data | length | name | description | +------+---------+---------------------------------------------------------+ | ???? | 2 bytes | num_cols | Number of columns stored on this row. | | ???? | n bytes | fixed_cols | Fixed length columns | | ???? | n bytes | var_cols | Variable length columns | | ???? | 2 bytes | eod | length of data from begining of record | | ???? | n bytes | var_table[]| offset from start of row for each var_col | | ???? | 2 bytes | var_len | number of variable length columns | | ???? | n bytes | null_mask | Null indicator. See notes. | +--------------------------------------------------------------------------+ Notes: . A row will always have the number of fixed columns as specified in the table definition, but may have fewer variable columns, as rows are not updated when columns are added. . All fixed-length columns are stored first to last, followed by non-null variable-length columns stored first to last. . If the number of variable columns, as given in the TDEF, is 0, then the only items in the row are num_cols, fixed_cols, and null_mask. . The var_len field indicates the number of entries in the var_table[]. . The var_table[] and jump_table[] are stored in reverse order. . The eod field points at the first byte after the var_cols field. It is used to determine where the last var_col ends. . The size of the null mask is computed by (num_cols + 7)/8. . Fixed columns can be null (unlike some other databases). . The null mask stores one bit for each column, starting with the least-significant bit of the first byte. . In the null mask, 0 represents null, and 1 represents not null. . Values for boolean fixed columns are in the null mask: 0 - false, 1 - true. In Jet3, offsets are stored as 1-byte fields yielding a maximum of 256 bytes. To get around this, offsets are computed using a jump table. The jump table stores the number of the first column in each jump segment. If the size of the row is less than 256 then the jump table will not be present. Also, eod is treated as an additional entry of the var_table[]. For example, if the row contains 45 columns and the 15th column is the first with an offset of 256 or greater, then the first entry in the jump table will be 0xe (14). If the 24th column is the first one at offset >= 512, the second entry of the jump table would be 0x17 (23). If eod is the first entry >= 768, the last entry in this case will be 0x2d (45). The number of jump table entries is calculated based on the size of the row, rather than the location of eod. As a result, there may be a dummy entry that contains 0xff. In this case, and using the example above, the values in the jump table would be 0x2d 0x17 0x0e 0xff. In Jet4 all offsets are stored as 2 byte fields, including the var_table entries. Thus, the jump table was (thankfully) ditched in Jet4. Each memo column (or other long binary data) in a row +-------------------------------------------------------------------------+ | Memo Field Definition (12 bytes) | +------+---------+-------------+------------------------------------------+ | data | length | name | description | +------+---------+-------------+------------------------------------------+ | ???? | 3 bytes | memo_len | Total length of the memo | | ???? | 1 bytes | bitmask | See values | | ???? | 4 bytes | lval_dp | Data pointer to LVAL page (if needed) | | 0x00 | 4 bytes | unknown | | +------+---------+-------------+------------------------------------------+ Values for the bitmask: 0x80 = the memo is in a string at the end of this header (memo_len bytes) 0x40 = the memo is in a unique LVAL page in a record type 1 0x00 = the memo is in n LVAL pages in a record type 2 If the memo is in a LVAL page, we use row_id of lval_dp to find the row. offset_start of memo = (int16*) LVAL_page[offset_num_rows + (row_id * 2) + 2] if (row_id = 0) offset_stop of memo = 2048(jet3) or 4096(jet4) else offset_stop of memo = (int16*) LVAL_page[offset_num_row + (row_id * 2)] The length (partial if type 2) for the memo is: memo_page_len = offset_stop - offset_start Update: The bitmask can't be an entire byte long. OLE fields can hold up to 1gig. That requires at least 30 bits, leaving only 2 bits for flags. Maybe sometimes 0xC0000000 is ignored? See http://office.microsoft.com/en-us/access-help/access-2007-specifications-HA010030739.aspx Number of characters in a Memo field: 65,535 when entering data through the user interface; 2 gigabytes of character storage when entering data programmatically. That would mean 31 bits for length. Note: if a memo field is marked for compression, only at value which is at most 1024 characters when uncompressed can be compressed. fields longer than that _must_ be stored uncompressed. LVAL (Long Value) Pages ----------------------- The header of a LVAL page is just like that of a regular data page, except that in place of the tdef_pg is the word 'LVAL'. Each memo record type 1 looks like this: +------+---------+-------------+------------------------------------------+ | data | length | name | description | +------+---------+-------------+------------------------------------------+ | ???? | n bytes | memo_value | A string which is the memo | +-------------------------------------------------------------------------+ Each memo record type 2 looks like this: +------+---------+-------------+------------------------------------------+ | data | length | name | description | +------+---------+-------------+------------------------------------------+ | ???? | 4 bytes | lval_dp | Next page LVAL type 2 if memo is too long| | ???? | n bytes | memo_value | A string which is the memo (partial) | +-------------------------------------------------------------------------+ In a LVAL type 2 data page, you have 10 or 14 bytes for the header of the data page, 2 bytes for an offset, 4 bytes for the next lval_pg So there is a block of 2048 - (10+2+4) = 2032(jet3) or 4096 - (14+2+4) = 4076(jet4) bytes max in a page. TDEF (Table Definition) Pages ----------------------------- Every table in the database has a TDEF page. It contains a definition of the columns, types, sizes, indexes, and similar information. +-------------------------------------------------------------------------+ | Jet3/Jet4 TDEF Header +------+---------+-------------+------------------------------------------+ | data | length | name | description | +------+---------+-------------+------------------------------------------+ | 0x02 | 1 bytes | page_type | 0x02 indicate a tabledef page | | 0x01 | 1 bytes | unknown | | | ???? | 2 bytes | tdef_id | (jet3) The word 'VC' | | | | | (jet4) Free space in this page minus 8 | | 0x00 | 4 bytes | next_pg | Next tdef page pointer (0 if none) | +------+---------+-------------+------------------------------------------+ TDEFs can span multiple pages for large tables, this is accomplished using the next_pg field. +-------------------------------------------------------------------------+ | Jet3 Table Definition Block (35 bytes) | +------+---------+-------------+------------------------------------------+ | data | length | name | description | +------+---------+-------------+------------------------------------------+ | ???? | 4 bytes | tdef_len | Length of the data for this page | | ???? | 4 bytes | num_rows | Number of records in this table | | 0x00 | 4 bytes | autonumber | value for the next value of the | | | | | autonumber column, if any. 0 otherwise | | 0x4e | 1 byte | table_type | 0x4e: user table, 0x53: system table | | ???? | 2 bytes | max_cols | Max columns a row will have (deletions) | | ???? | 2 bytes | num_var_cols| Number of variable columns in table | | ???? | 2 bytes | num_cols | Number of columns in table (repeat) | | ???? | 4 bytes | num_idx | Number of logical indexes in table | | ???? | 4 bytes | num_real_idx| Number of index entries | | ???? | 4 bytes | used_pages | Points to a record containing the | | | | | usage bitmask for this table. | | ???? | 4 bytes | free_pages | Points to a similar record as above, | | | | | listing pages which contain free space. | +-------------------------------------------------------------------------+ | Iterate for the number of num_real_idx (8 bytes per idxs) | +-------------------------------------------------------------------------+ | 0x00 | 4 bytes | ??? | | | ???? | 4 bytes | num_idx_rows| (not sure) | +-------------------------------------------------------------------------+ | Iterate for the number of num_cols (18 bytes per column) | +-------------------------------------------------------------------------+ | ???? | 1 byte | col_type | Column Type (see table below) | | ???? | 2 bytes | col_num | Column Number (includes deleted columns) | | ???? | 2 bytes | offset_V | Offset for variable length columns | | ???? | 2 bytes | col_num | Column Number | | ???? | 2 bytes | sort_order | textual column sort order(0x409=General) | | ???? | 2 bytes | misc | prec/scale (1 byte each), or code page | | | | | for textual columns (0x4E4=cp1252) | | ???? | 2 bytes | ??? | | | ???? | 1 byte | bitmask | See Column flags bellow | | ???? | 2 bytes | offset_F | Offset for fixed length columns | | ???? | 2 bytes | col_len | Length of the column (0 if memo) | +-------------------------------------------------------------------------+ | Iterate for the number of num_cols (n bytes per column) | +-------------------------------------------------------------------------+ | ???? | 1 byte | col_name_len| len of the name of the column | | ???? | n bytes | col_name | Name of the column | +-------------------------------------------------------------------------+ | Iterate for the number of num_real_idx (30+9 = 39 bytes) | +-------------------------------------------------------------------------+ | Iterate 10 times for 10 possible columns (10*3 = 30 bytes) | +-------------------------------------------------------------------------+ | ???? | 2 bytes | col_num | number of a column (0xFFFF= none) | | ???? | 1 byte | col_order | 0x01 = ascendency order | +-------------------------------------------------------------------------+ | ???? | 4 bytes | used_pages | Points to usage bitmap for index | | ???? | 4 bytes | first_dp | Data pointer of the index page | | ???? | 1 byte | flags | See flags table for indexes | +-------------------------------------------------------------------------+ | Iterate for the number of num_idx (20 bytes) | +-------------------------------------------------------------------------+ | ???? | 4 bytes | index_num | Number of the index | | | | |(warn: not always in the sequential order)| | ???? | 4 bytes | index_num2 | Index into index cols list | | 0x00 | 1 byte | rel_tbl_type| type of the other table in this fk | | | | | (same values as index_type) | | 0xFF | 4 bytes | rel_idx_num | index number of other index in fk | | | | | (or -1 if this index is not a fk) | | 0x00 | 4 bytes | rel_tbl_page| page number of other table in fk | | 0x01 | 1 byte | cascade_ups | flag indicating if updates are cascaded | | 0x01 | 1 byte | cascade_dels| flag indicating if deletes are cascaded | | ???? | 1 byte | index_type | 0x01 if index is primary, 0x02 if foreign| +-------------------------------------------------------------------------+ | Iterate for the number of num_idx | +-------------------------------------------------------------------------+ | ???? | 1 byte | idx_name_len| len of the name of the index | | ???? | n bytes | idx_name | Name of the index | +-------------------------------------------------------------------------+ | Iterate while col_num != 0xffff | +-------------------------------------------------------------------------+ | ???? | 2 bytes | col_num | Column number with variable length | | ???? | 4 bytes | used_pages | Points to a record containing the | | | | | usage bitmask for this column. | | ???? | 4 bytes | free_pages | Points to a similar record as above, | | | | | listing pages which contain free space. | +-------------------------------------------------------------------------+ +-------------------------------------------------------------------------+ | Jet4 Table Definition Block (55 bytes) | +------+---------+-------------+------------------------------------------+ | data | length | name | description | +------+---------+-------------+------------------------------------------+ | ???? | 4 bytes | tdef_len | Length of the data for this page | | ???? | 4 bytes | unknown | unknown | | ???? | 4 bytes | num_rows | Number of records in this table | | 0x00 | 4 bytes | autonumber | value for the next value of the | | | | | autonumber column, if any. 0 otherwise | | 0x01 | 1 byte | autonum_flag| 0x01 makes autonumbers work in access | | ???? | 3 bytes | unknown | unknown | | 0x00 | 4 bytes | ct_autonum | autonumber value for complex type column(s) | | | | | (shared across all columns in the table) | | ???? | 8 bytes | unknown | unknown | | 0x4e | 1 byte | table_type | 0x4e: user table, 0x53: system table | | ???? | 2 bytes | max_cols | Max columns a row will have (deletions) | | ???? | 2 bytes | num_var_cols| Number of variable columns in table | | ???? | 2 bytes | num_cols | Number of columns in table (repeat) | | ???? | 4 bytes | num_idx | Number of logical indexes in table | | ???? | 4 bytes | num_real_idx| Number of index entries | | ???? | 4 bytes | used_pages | Points to a record containing the | | | | | usage bitmask for this table. | | ???? | 4 bytes | free_pages | Points to a similar record as above, | | | | | listing pages which contain free space. | +-------------------------------------------------------------------------+ | Iterate for the number of num_real_idx (12 bytes per idxs) | +-------------------------------------------------------------------------+ | 0x00 | 4 bytes | ??? | | | ???? | 4 bytes | num_idx_rows| (not sure) | | 0x00 | 4 bytes | ??? | | +-------------------------------------------------------------------------+ | Iterate for the number of num_cols (25 bytes per column) | +-------------------------------------------------------------------------+ | ???? | 1 byte | col_type | Column Type (see table below) | | ???? | 4 bytes | unknown | matches first unknown definition block | | ???? | 2 bytes | col_num | Column Number (includes deleted columns) | | ???? | 2 bytes | offset_V | Offset for variable length columns | | ???? | 2 bytes | col_num | Column Number | | ???? | 2 bytes | misc | prec/scale (1 byte each), or sort order | | | | | for textual columns(0x409=General) | | | | | or "complexid" for complex columns (4bytes)| | ???? | 2 bytes | misc_ext | text sort order version num is 2nd byte | | ???? | 1 byte | bitmask | See column flags below | | ???? | 1 byte | misc_flags | 0x01 for compressed unicode | | 0000 | 4 bytes | ??? | | | ???? | 2 bytes | offset_F | Offset for fixed length columns | | ???? | 2 bytes | col_len | Length of the column (0 if memo/ole) | +-------------------------------------------------------------------------+ | Iterate for the number of num_cols (n*2 bytes per column) | +-------------------------------------------------------------------------+ | ???? | 2 bytes | col_name_len| len of the name of the column | | ???? | n bytes | col_name | Name of the column (UCS-2 format) | +-------------------------------------------------------------------------+ | Iterate for the number of num_real_idx (30+22 = 52 bytes) | +-------------------------------------------------------------------------+ | ???? | 4 bytes | ??? | | +-------------------------------------------------------------------------+ | Iterate 10 times for 10 possible columns (10*3 = 30 bytes) | +-------------------------------------------------------------------------+ | ???? | 2 bytes | col_num | number of a column (0xFFFF= none) | | ???? | 1 byte | col_order | 0x01 = ascendency order | +-------------------------------------------------------------------------+ | ???? | 4 bytes | used_pages | Points to usage bitmap for index | | ???? | 4 bytes | first_dp | Data pointer of the index page | | ???? | 1 byte | flags | See flags table for indexes | | ???? | 9 bytes | unknown | | +-------------------------------------------------------------------------+ | Iterate for the number of num_idx (28 bytes) | +-------------------------------------------------------------------------+ | ???? | 4 bytes | unknown | matches first unknown definition block | | ???? | 4 bytes | index_num | Number of the index | | | | |(warn: not always in the sequential order)| | ???? | 4 bytes | index_num2 | Index into index cols list | | 0x00 | 1 byte | rel_tbl_type| type of the other table in this fk | | | | | (same values as index_type) | | 0xFF | 4 bytes | rel_idx_num | index number of other index in fk | | | | | (or -1 if this index is not a fk) | | 0x00 | 4 bytes | rel_tbl_page| page number of other table in fk | | 0x01 | 1 byte | cascade_ups | flag indicating if updates are cascaded | | 0x01 | 1 byte | cascade_dels| flag indicating if deletes are cascaded | | ???? | 1 byte | index_type | 0x01 if index is primary, 0x02 if foreign| +-------------------------------------------------------------------------+ | Iterate for the number of num_idx | +-------------------------------------------------------------------------+ | ???? | 2 bytes | idx_name_len| len of the name of the index | | ???? | n bytes | idx_name | Name of the index (UCS-2) | +-------------------------------------------------------------------------+ | Iterate while col_num != 0xffff | +-------------------------------------------------------------------------+ | ???? | 2 bytes | col_num | Column number with variable length | | ???? | 4 bytes | used_pages | Points to a record containing the | | | | | usage bitmask for this column. | | ???? | 4 bytes | free_pages | Points to a similar record as above, | | | | | listing pages which contain free space. | +-------------------------------------------------------------------------+ Columns flags (not complete): 0x01: fixed length column 0x02: can be null (possibly related to joins?) 0x04: is auto long 0x10: replication related field (or hidden?). These columns start with "s_" or "Gen_" (the "Gen_" fields are for memo fields) 0x40: is auto guid 0x80: hyperlink. Syntax is "Link Title#http://example.com/somepage.html#" or "#PAGE.HTM#" In Access 2007 and Access 2010, "Complex Columns" (multivalued fields, version history, attachments) always have the flag byte set to exactly 0x07. Index flags (not complete): 0x01 Unique 0x02 IgnoreNuls 0x08 Required Column Type may be one of the following (not complete): BOOL = 0x01 /* Boolean ( 1 bit ) */ BYTE = 0x02 /* Byte ( 8 bits) */ INT = 0x03 /* Integer (16 bits) */ LONGINT = 0x04 /* Long Integer (32 bits) */ MONEY = 0x05 /* Currency (64 bits) */ FLOAT = 0x06 /* Single (32 bits) */ DOUBLE = 0x07 /* Double (64 bits) */ DATETIME = 0x08 /* Date/Time (64 bits) */ BINARY = 0x09 /* Binary (255 bytes) */ TEXT = 0x0A /* Text (255 bytes) */ OLE = 0x0B /* OLE = Long binary */ MEMO = 0x0C /* Memo = Long text*/ UNKNOWN_0D = 0x0D UNKNOWN_0E = 0x0E REPID = 0x0F /* GUID */ NUMERIC = 0x10 /* Scaled decimal (17 bytes) */ Notes on reading index metadata: There are 2 types of index metadata, "physical" index info (denoted by num_real_idx) and "logical" index info (denoted by num_idx). Normally, there is a 1 to 1 relationship between these 2 types of information. However there can be more logical index infos than physical index infos (currently only seen for foreign key indexes). In this situation, one or more of the logical indexes actually share the same underlying physical index (the index_num2 indicates which physical index backs which logical index). As noted in the previous paragraph, physical index sharing is generally only seen when a foreign key index has been created. When access creates a relationship between 2 tables with "enforce referential integrity" enabled, each of the tables gets an extra logical index with type 2 (foreign key). These logical indexes contain extra information, primarily pointers to the related table (rel_tbl_page) and logical index (rel_idx_num). Also, the rel_tbl_type value indicates which table in the relationship is the "primary" table (the one one from which cascaded updates/deletes flow). If the indexed columns for the foreign key are already indexed by another logical index in the table (e.g. an index which the user has explicitly created), then the logical foreign key index will simply share the underlying physical index data. Notes on deleted and added columns: (sort of Jet4 specific) If a fixed length column is deleted the offset_F field will contain the offsets of the original row definition. Thus if the number of columns on the row does not match the number in the tdef, the offset_F field could be used to return the proper data. Columns are never really deleted in the row data. The deleted column will forever exist and be set to null for new rows. A row may have less than max_cols columns but will never have more, as max_cols is never decremented. If you have a table with 6 columns, delete one, and add one, then max_cols will be 7. For variable length columns, offset_V will hold the position in the offset table of that column. Missing columns are set to null for new rows. Page Usage Maps --------------- There are three uses for the page usage bitmaps. There is a global page usage stored on page 1 which tracks allocated pages throughout the database. Tables store two page usage bitmaps. One is a straight map of which pages are owned by the table. The second is a map of the pages owned by the table which have free space on them (used for inserting data). The table bitmaps appear to be of a fixed size for both Jet 3 and 4 (128 and 64 bytes respectively). The first byte of the map is a type field. +--------------------------------------------------------------------------+ | Type 0 Page Usage Map | +------+---------+---------------------------------------------------------+ | data | length | name | description | +------+---------+---------------------------------------------------------+ | 0x00 | 1 byte | map_type | 0x00 indicates map stored within. | | ???? | 4 byte | page_start | first page for which this map applies | +------+---------+---------------------------------------------------------+ | Iterate for the length of map | +--------------------------------------------------------------------------+ | ???? | 1 byte | bitmap | each bit encodes the allocation status of a| | | | | page. 1 indicates allocated to this table. | | | | | Pages are stored starting with the low | | | | | order bit of the first byte. | +--------------------------------------------------------------------------+ If you're paying attention then you'll realize that the relatively small size of the map (128*8*2048 or 64*8*4096 = 2 Meg) means that this scheme won't work with larger database files although the initial start page helps a bit. To overcome this there is a second page usage map scheme with the map_type of 0x01. +--------------------------------------------------------------------------+ | Type 1 Page Usage Map | +------+---------+---------------------------------------------------------+ | data | length | name | description | +------+---------+---------------------------------------------------------+ | 0x01 | 1 byte | map_type | 0x01 indicates this is a indirection list. | +------+---------+---------------------------------------------------------+ | Iterate for the length of map | +--------------------------------------------------------------------------+ | ???? | 4 bytes | map_page | pointer to page type 0x05 containing map | +--------------------------------------------------------------------------+ Note that the initial start page is gone and is reused for the first page indirection. The 0x05 type page header looks like: +--------------------------------------------------------------------------+ | Usage Map Page (type 0x05) | +------+---------+---------------------------------------------------------+ | data | length | name | description | +------+---------+---------------------------------------------------------+ | 0x05 | 1 byte | page_type | allocation map page | | 0x01 | 1 byte | unknown | always 1 as with other page types | | 0x00 | 2 bytes | unknown | | +------+---------+---------------------------------------------------------+ The rest of the page is the allocation bitmap following the same scheme (lsb to msb order, 1 bit per page) as a type 0 map. This yields a maximum of 2044*8=16352 (jet3) or 4092*8 = 32736 (jet4) pages mapped per type 0x05 page. Given 128/4+1 = 33 or 64/4+1 = 17 page pointers per indirection row (remember the start page field is reused, thus the +1), this yields 33*16352*2048 = 1053 Meg (jet3) or 17*32736*4096 = 2173 Meg (jet4) or enough to cover the maximum size of each of the database formats comfortably, so there is no reason to believe any other page map schemes exist. Indices ------- Indices are not completely understood but here is what we know. +-------------------------------------------------------------------------+ | Index Page (type 0x03) | +------+---------+-------------+------------------------------------------+ | data | length | name | description | +------+---------+-------------+------------------------------------------+ | 0x01 | 1 bytes | page_type | 0x03 indicate an index page | | 0x01 | 1 bytes | unknown | | | ???? | 2 bytes | free_space | The free space at the end this page | | ???? | 4 bytes | parent_page | The page number of the TDEF for this idx | | ???? | 4 bytes | prev_page | Previous page at this index level | | ???? | 4 bytes | next_page | Next page at this index level | | ???? | 4 bytes | tail_page | Pointer to tail leaf page | | ???? | 2 bytes | pref_len | Length of the shared entry prefix | +-------------------------------------------------------------------------+ Index pages come in two flavors. 0x04 pages are leaf pages which contain one entry for each row in the table. Each entry is composed of a flag, the indexed column values and a page/row pointer to the data. 0x03 index pages make up the rest of the index tree and contain a flag, the indexed columns, the page/row that contains this entry, and the leaf page or intermediate (another 0x03 page) page pointer for which this is the first entry on. Both index types have a bitmask starting at 0x16(jet3) or 0x1b(jet4) which identifies the starting location of each index entry on this page. The first entry begins at offset 0xf8(jet3) or 0x1e0(jet4), and is not explicitly indicated in the bitmask. Note that the count in each byte begins with the low order bit. For example take the data: 00 20 00 04 80 00 ... Convert the bytes to binary starting with the low order bit in each byte. v's mark where each entry begins: v v v v 0000 0000 0000 0100 0000 0000 0010 0000 0000 0001 0000 0000 -- 00 --- -- 20 --- -- 00 --- -- 04 --- -- 80 --- -- 00 --- As noted earlier, the first entry is implicit. The second entry begins at an offset of 13 (0xd) bytes from the first. The third entry 26 (0x1a) bytes from the first. The final entry starts at an offset of 39 (0x27) bytes from the first. In this example the rest of the mask (up to offset 0xf8/0x1e0) would be zero-filled and thus this last entry isn't an actual entry, but the stopping point of the data. For Jet3, (0xf8 - 0x16) * 8 = 0x710 and 0x800 - 0xf8 = 0x708. For Jet4, (0x1e0 - 0x1b) * 8 = 0xe28 and 0x1000 - 0x1e0 = 0xe20. So the mask just covers the page, including space to indicate if the last entry goes to the end of the page. One wonders why MS didn't use a row offset table like they did on data pages. It seems like it would have been easier and more flexible. So now we come to the index entries for type 0x03 pages which look like this: +-------------------------------------------------------------------------+ | Index Record | +------+---------+-------------+------------------------------------------+ | data | length | name | description | +------+---------+-------------+------------------------------------------+ | 0x7f | 1 byte | flags | 0x80 LSB, 0x7f MSB, 0x00 null? | | ???? | variable| indexed cols| indexed column data | | ???? | 3 bytes | data page | page containing row referred to by this | | | | | index entry | | ???? | 1 byte | data row | row number on that page of this entry | | ???? | 4 bytes | child page | next level index page containing this | | | | | entry as last entry. Could be a leaf | | | | | node. | +-------------------------------------------------------------------------+ The flag field is generally either 0x00, 0x7f, 0x80, or 0xFF. 0x80 is the one's complement of 0x7f and all text data in the index would then need to be negated. The reason for this negation is descending order. The 0x00 flag indicates that the key column is null (or 0xFF for descending order), and no data will follow, only the page pointer. In multicolumn indexes the flag field plus data is repeated for the number of columns participating in the key. Index entries are always sorted based on the lexicographical order of the entry bytes of the entire index entry (thus descending order is achieved by negating the bytes). The flag field ensures that null values are always sorted at the beginning (for ascending) or end (for descending) of the index. Note, there is a compression scheme utilizing a shared entry prefix. If an index page has a shared entry prefix (idicated by a pref_len > 0), then the first pref_len bytes from the first entry need to be pre-pended to every subsequent entry on the page to get the full entry bytes. For example, normally an index entry with an integer primary key would be 9 bytes (1 for the flags field, 4 for the integer, 4 for page/row). If the pref_len on the index page were 4, every entry after the first would then contain only 5 bytes, where the first byte is the last octet of the encoded primary key field (integer) and the last four are the page/row pointer. Thus if the first key value on the page is 1 and it points to page 261 (00 01 05) row 3, it becomes: 7f 00 00 00 01 00 01 05 03 and the next index entry can be: 02 00 01 05 04 That is, the shared prefix is [7f 00 00 00], so the actual next entry is: [7f 00 00 00] 02 00 01 05 04 so the key value is 2 (the last octet changes to 02) page 261 row 4. Access stores an 'alphabetic sort order' version of the text key columns in the index. Here is the encoding as we know it: 0-9: 0x56-0x5f A-Z: 0x60-0x79 a-z: 0x60-0x79 Once converted into this (non-ascii) character set, the text value can be sorted in 'alphabetic' order using the lexicographical order of the entry bytes. A text column will end with a NULL (0x00 or 0xff if negated). Note, this encoding is the "General" sort order in Access 2000-2007 (1033, version 0). As of Access 2010, this is now called the "General legacy" sort order, and the 2010 "General" sort order is a new encoding (1033, vesion 1). The leaf page entries store the key column and the 3 byte page and 1 byte row number. The value of the index root page in the index definition may be an index page (type 0x03), an index leaf page (type 0x04) if there is only one index page, or (in the case of tables small enough to fit on one page) a data page (type 0x01). So to search the index, you need to convert your value into the alphabetic character set, compare against each index entry, and on successful comparison follow the page and row number to the data. Because text data is managled during this conversion there is no 'covered querys' possible on text columns. To conserve on frequent index updates, Jet also does something special when creating new leaf pages at the end of a primary key index (or other index where new values are generally added to the end of the index). The tail leaf page pointer of the last leaf node points to the new leaf page but the index tree is not otherwise updated. Since index entries in type 0x03 index pages point to the last entry in the page, adding a new entry to the end of a large index would cause updates all the way up the index tree. Instead, the tail page can be updated in isolation until it is full, and then moved into the index proper. In src/libmdb/index.c, the last leaf read is stored, once the index search has been exhausted by the normal search routine, it enters a "clean up mode" and reads the next leaf page pointer until it's null. Properties ---------- Design View table definitions are stored in LvProp column of MSysObjects as OLE fields. They contain default values, description, format, required ... They start with a 32 bits header: 'KKD\0' in Jet3 and 'MR2\0' in Jet 4. Next come chunks. Each chunk starts with: 32 bits length value (this includes the length) 16 bits chunk type (0x0080 contains the names, 0x0000 and 0x0001 contain the values. 0x0000 seems to contain information about the "main" object, e.g. the table, and 0x0001 seems to contain information about other objects, e.g. the table columns) Name chunk blocks (0x0080) simply contain occurences of: 16 bit name length name For instance: 0x0d 0x00 and 'AccessVersion' (AccessVersion is 13 bytes, 0x0d 0x00 intel order) Value chunk blocks (0x0000 and 0x0001) contain a header: 32 bits length value (this includes the length) 16 bits name length name (0x0000 chunk blocks are not usually named, 0x0001 chunk blocks have the column name to which the properties belong) Next comes one of more chunks of data: 16 bit length value (this includes the length) 8 bit unknown flag 8 bit type 16 bit name (index in the name array of above chunk 0x0080) 16 bit value length field (non-inclusive) value (07.53 for the AccessVersion example above) See props.c for an example. Text Data Type -------------- In Jet3, the encoding of text depends on the machine on which it was created. So for databases created on U.S. English systems, it can be expected that text is encoded in CP1252. This is the default used by mdbtools. If you know that another encoding has been used, you can over-ride the default by setting the environment variable MDB_JET3_CHARSET. To find out what encodings will work on your system, run 'iconv -l'. In Jet4, the encoding can be either little-endian UCS-2, or a special compressed form of it. This compressed format begins with 0xff 0xfe. The string then starts in compressed mode, where characters with 0x00 for the most-significant byte do not encode it. In the compressed format, a 0x00 byte signals a change from compressed mode to uncompressed mode, or from uncompressed mode back to compressed mode. The string may end in either mode. Note that a string containing any character 0x##00 (UCS-2) will not be compressed. Also, the string will only be compressed if it really does make the string shorter as compared to uncompressed UCS-2. Programs that use mdbtools libraries will receive strings encoded in UTF-8 by default. This default can by over-ridden by setting the environment variable MDBICONV to the desired encoding. mdbtools-0.7.1/Makefile.am000066400000000000000000000003051222645741400154030ustar00rootroot00000000000000ACLOCAL_AMFLAGS = -I m4 SUBDIRS = src include doc DEFDIR = $(prefix) EXTRA_DIST = HACKING libmdb.pc.in libmdbsql.pc.in pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libmdb.pc libmdbsql.pc mdbtools-0.7.1/NEWS000066400000000000000000000013511222645741400140500ustar00rootroot00000000000000Version 0.7.1 ============= autogen.sh is no more. Use "autoreconf -if" to bootstrap the configuration. autoconf/automake has been updated to more recent standards. - config.guess config.sub depcomp install-sh ltmain.sh missing ylwrap files are now in build-aux/ directory You'll now need autoconf >= 2.58 An experimental (buggy) version of ODBC driver that supports UCS-2 interface is now available: libmdbodbcW.so Note that libmdbodbc supports UTF-8 really well, so that this is usually not needed. Version 0.3 =========== The organization of the project files has changed a bit from that last release. The autoconf stuff has been moved to the root directory. The include directory has also been moved from src/include to include mdbtools-0.7.1/README000066400000000000000000000116711222645741400142370ustar00rootroot00000000000000This is mdbtools version 0.7.1 Welcome to the exciting world of MDB Tools! In short, MDB Tools is a set of programs to help you use Microsoft Access file in various settings. The major pieces are: . libmdb - the core library that allows access to MDB files programatically. . libmdbsql - builds on libmdb to provide a SQL engine (aka Jet) . utils - provides command line utilities: mdb-ver -- prints the version (JET 3 or 4) of an mdb file. mdb-dump -- simple hex dump utility that I've been using to look at mdb files. mdb-schema -- prints DDL for the specified table. mdb-export -- export table to CSV format. mdb-tables -- a simple dump of table names to be used with shell scripts mdb-header -- generates a C header to be used in exporting mdb data to a C prog. mdb-parsecvs -- generates a C program given a CSV file made with mdb-export mdb-sql -- if --enable-sql is specified, a simple SQL engine (also used by ODBC and gmdb). - And some utilities useful for debugging: prcat -- prints the catalog table from an mdb file. prkkd -- dump of information about design view data given the offset to it. prtable -- dump of a table definition. prdata -- dump of the data given a table name. prole -- dump of ole columns given a table name and sargs. . mdb-sql - a command line SQL tool that allows one to type sql queries and get results. . odbc - An ODBC driver for use with unixODBC or iODBC driver manager. Allows one to use MDB files with PHP for example. . gmdb2 - The Gnome MDB File Viewer and debugger. Still alpha, but making great progress. If you are interested in helping, read the HACKING file for a description of where the code stands and what has been gleened of the file format. The initial goal of these tools is to be able to extract data structures and data from mdb files. This goal will of course expand over time as the file format becomes more well understood. Files in libmdb, libmdbsql, and libmdbodbc are licensed under LGPL and the utilities and gui program are under the GPL, see COPYING.LIB and COPYING files respectively. Requirements: ============= First, you must have reasonably current installations of: libtool automake autoconf (version >= 2.58) If you don't you should install them first. Sources are available at ftp.gnu.org. If you want to build the SQL engine, you'll need bison or byacc, and flex. If you want to build the ODBC driver, you'll need unixodbc (version 2.2.10 or above) or iodbc. If you want to build man pages, you'll need txt2man. Source is available at http://mvertes.free.fr/download/. If you want to generate the html version of the docbook, you'll need openjade and basic dsl catalogs. Installation from source: ========================= Last version is available at https://github.com/brianb/mdbtools $ autoreconf -i -f If you want to build the html version of the docbook documentation, you need to set the environment variable DOCBOOK_DSL to the modular dsl translation file. For exemple, before configure, you need something like: $ export DOCBOOK_DSL=/usr/share/sgml/docbook/stylesheet/dsssl/modular/html/docbook.dsl $ ./configure OR for a complete install (requires bison, flex, and unixODBC): $ ./configure --with-unixodbc=/usr/local configure can be passed any of the following flags to turn on other capabilities. Note that the options --with-unixodbc and --with-iodbc are mutually exclusive. --with-unixodbc specifies the location of the unixODBC driver manager and causes the unixODBC driver to be built. --with-iodbc specifies the location of the iODBC driver manager and causes the iODBC driver to be built. A list of general options is available in the INSTALL file, and "configure --help" will give you the list of mdbtools specific options. $ make Once MDB Tools has been compiled, libmdb.[so|a] will be in the src/libmdb directory and the utility programs will be in the src/util directory. You can then run 'make install' as root to install (to /usr/local by default). Some systems will also need the ld cache to be updated after installation; You can do that running 'ldconfig' as root. Contacts ======== The mailing list from the old site a available at http://mdbtools.sourceforge.net Please send bug repports to the new github platform. https://github.com/brianb/mdbtools/issues Brian Bruns brian@bruns.com P.S. I, like many other free software authors enjoy receiving postcards from the places users of my software live. So, if you enjoy the software and it has helped you out, consider sending me one, eh? Just email me for my postal address. mdbtools-0.7.1/TODO000066400000000000000000000032311222645741400140400ustar00rootroot00000000000000Things to Do ------------ general: . compile with -Wall and fix warnings (done) file format: . how does global allocation map work? (done) . export VBA script . re-examine KKD records for form design (OLE streams?) . write support (understood, not coded) libmdb: . Complete the list of datatypes . Straighten out which functions in libmdb are meant to be used and which ones should be static. . Create an API reference for libmdb (maybe some man pages). . Sargs need to support all datatypes . Need a way to express logical relationships between sargs (done) . Add support for index scanning when using sargs (partial) . Use allocation maps to read tables, should be more efficient (done) . write support . iconv conversion to utf-8, et al. (done) . multipage work tables (done) utils: . need program to unpack VBA script to file (see prole) . Access forms to glade converter ? . need --version flag (done using -M flag on mdb-ver) . -o on mdb-sql not working (done) SQL Engine: . SQL Engine does not handle uppercase keywords (done) . Joins . OR clauses using sarg trees from above (done) . insert/updates . bogus column name in where clause not caught . const = const type operations not working (e.g. WHERE 0=1) (done) . list tables/describe table shouldn't directly write to stdout (done) ODBC: . Figure out why we get unresolved symbols when ODBC driver load by DM (iODBC only) . Boolean not working (done) . many unimplemented funtions GMDB: . Finish debug dissectors . Export schema not implemented (done) . Printing not implemented . Export needs finishing (done) . Fix bitmask size bug in debugger . sql window section in manual . debugger section in manual mdbtools-0.7.1/configure.ac000066400000000000000000000136751222645741400156530ustar00rootroot00000000000000dnl Process this file with autoconf to produce a configure script. AC_INIT([mdbtools],[0.7.1],[mdbtools-dev@lists.sourceforge.net]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_SRCDIR(src/extras/mdb-dump.c) AM_INIT_AUTOMAKE AM_MAINTAINER_MODE([enable]) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) AC_PROG_CC(gcc) dnl Checks for programs. AC_PROG_MAKE_SET AM_PROG_AR LT_INIT AC_PROG_LEX AC_PROG_YACC dnl Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS(fcntl.h limits.h unistd.h) AC_CHECK_HEADERS(wordexp.h) dnl Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_TYPE_SIZE_T AM_ICONV AM_GCC_ATTRIBUTE_ALIAS dnl no optional stuff by default OPTDIRS="" dnl --------------------------------------------------------------------- dnl Compile time options dnl --------------------------------------------------------------------- sql=true AC_MSG_CHECKING( Are we using flex ) if test "x$LEX" = "xflex"; then LFLAGS="$LFLAGS -i -8" AC_MSG_RESULT( yes ); else AC_MSG_RESULT( no - SQL engine disable); sql=false fi if ! $YACC -V >/dev/null 2>&1; then sql=false fi if test "x$sql" = "xtrue"; then CFLAGS="$CFLAGS -DSQL" OPTDIRS="$OPTDIRS sql" else AC_MSG_WARN([Yacc is not available: SQL disabled.]) fi AM_CONDITIONAL(SQL, test x$sql = xtrue) AC_SUBST(SQL) AC_SUBST(LFLAGS) CFLAGS="$CFLAGS -Wall" dnl Enable -Wl,--as-needed by default to prevent overlinking AC_ARG_ENABLE([as-needed], AS_HELP_STRING([--disable-as-needed],[Disable overlinking protection]), [enable_as_needed=$enableval], [enable_as_needed=yes]) if test "x$enable_as_needed" != "xno"; then AC_MSG_CHECKING([whether $LD accepts --as-needed]) case `$LD --as-needed -v 2>&1 = 2.14 libglade-2.0 libgnomeui-2.0, HAVE_GNOME=true, HAVE_GNOME=false) AC_ARG_ENABLE(gmdb2, AS_HELP_STRING([--disable-gmdb2],[do not build gmdb2]), [build_gmdb2=$enableval], [build_gmdb2=yes]) if test "$build_gmdb2" = "yes" ; then if test "x$HAVE_GNOME" = "xtrue"; then AC_SUBST(GNOME_CFLAGS) AC_SUBST(GNOME_LIBS) OPTDIRS="$OPTDIRS gmdb2" fi else AC_MSG_NOTICE(gmdb2 disabled) fi AC_SUBST([OPTDIRS]) AC_CONFIG_FILES([src/Makefile]) ################################################## # Check for gtk-doc. ################################################## AC_ARG_WITH(html-dir, [ --with-html-dir=PATH path to installed docs ]) if test "x$with_html_dir" = "x" ; then HTML_DIR='${datadir}/gtk-doc/html' else HTML_DIR=$with_html_dir fi AC_SUBST(HTML_DIR) gtk_doc_min_version=1.0 AC_MSG_CHECKING([gtk-doc version >= $gtk_doc_min_version]) if pkg-config --atleast-version=$gtk_doc_min_version gtk-doc; then AC_MSG_RESULT(yes) GTKDOC=true else AC_MSG_RESULT(no) GTKDOC=false fi dnl Let people disable the gtk-doc stuff. AC_ARG_ENABLE(gtk-doc, [ --enable-gtk-doc Use gtk-doc to build documentation [default=auto]], enable_gtk_doc="$enableval", enable_gtk_doc=auto) if test x$enable_gtk_doc = xauto ; then if test x$GTKDOC = xtrue ; then enable_gtk_doc=yes else enable_gtk_doc=no fi fi AM_CONDITIONAL(ENABLE_GTK_DOC, test x$enable_gtk_doc = xyes) ################################################## # Check for txt2man ################################################## AC_ARG_ENABLE(man, [ --disable-man Disable man generation], enable_man="$enableval", [enable_man=yes]) if test "$enable_man" = yes; then if ! which txt2man > /dev/null; then AC_MSG_ERROR([Could not find txt2man script. Install it or configure with --disable-man if you are not interrested in manuals.]) fi fi AM_CONDITIONAL(ENABLE_MAN, test "$enable_man" = yes) ################################################## # Check for docbook ################################################## AM_CONDITIONAL(ENABLE_DOCBOOK, test -n "$DOCBOOK_DSL") dnl Checks for library functions. VL_LIB_READLINE localedir=${datadir}/locale AC_SUBST(localedir) AC_CONFIG_FILES([ libmdb.pc libmdbsql.pc src/util/Makefile src/extras/Makefile Makefile include/Makefile src/libmdb/Makefile src/sql/Makefile src/odbc/Makefile doc/Makefile src/gmdb2/Makefile src/gmdb2/gladefiles/Makefile src/gmdb2/pixmaps/Makefile src/gmdb2/help/Makefile src/gmdb2/help/C/Makefile mdbtools.spec include/mdbver.h]) AC_OUTPUT dnl doc/reference/libmdb/Makefile]) mdbtools-0.7.1/doc/000077500000000000000000000000001222645741400141165ustar00rootroot00000000000000mdbtools-0.7.1/doc/Makefile.am000066400000000000000000000021621222645741400161530ustar00rootroot00000000000000SHELL = /bin/sh TXT2MAN = txt2man PRODUCT = MDBTools # To make the userguide, export DOCBOOK_DSL TO point to docbook.dsl. dist_man_MANS = if ENABLE_MAN dist_man_MANS += mdb-tables.1 mdb-ver.1 mdb-export.1 mdb-schema.1 mdb-sql.1 \ mdb-array.1 mdb-header.1 mdb-hexdump.1 mdb-parsecsv.1 mdb-prop.1 gmdb2.1 endif if ENABLE_DOCBOOK dist_man_MANS += install.tgz endif CLEANFILES = ${dist_man_MANS} install install.tgz EXTRA_DIST = mdb-tables.txt mdb-ver.txt mdb-export.txt mdb-schema.txt mdb-sql.txt \ mdb-array.txt mdb-header.txt mdb-hexdump.txt mdb-parsecsv.txt mdb-prop.txt gmdb2.txt \ faq.html install.sgml .txt.1: $(TXT2MAN) -t $* -r "$(PRODUCT) $(VERSION)" -s 1 -v "Executable programs or shell commands" $(srcdir)/$< > $@ # Converting DocBook to HTML (several small files) # http://www.freebsd.org/tutorials/docproj-primer/x3132.html#AEN3140 install.tgz: $(srcdir)/install.sgml rm -rf html mkdir html cd html && \ openjade -d ${DOCBOOK_DSL} -t sgml ../install.sgml [ -f html/book1.htm ] ln -s book1.htm html/index.html [ -L install ] || ln -s html install tar zcf install.tgz install/* clean-local: -rm -rf html mdbtools-0.7.1/doc/faq.html000066400000000000000000000124061222645741400155560ustar00rootroot00000000000000 The MDB Tools FAQ (Frequently Asked Questions)

    The MDB Tools FAQ

    1. General Questions
    1.1 What is an MDB
    1.2 What does MDB Tools do
    1.3 What are the tools in MDB Tools
    1.4 What license is MDB Tools under
    1.5 What Jet Databases does MDB Tools support?
    1.6 Is there a road map
    1.7 How do I install
    1.8 I've found a bug
    1.9 How do I help?
    1.10 What's this postcard thing?
    1.11 When will MDB Tools support writing?

    General Questions

    1.1 What is an MDB
    MDB databases are files produced by the Microsoft 'Jet' database engine. They are used in a variety of Microsoft products such as Money, Project, IIS, and Exchange as well as Accpac's Simply Accounting and Fog Creek's CityDesk, but most importantly, it is used as the format for Microsoft Access databases.
    1.2 What does MDB Tools do
    MDB Tools is an open source suite of libraries and utilities to read (and soon write) MDB database files.
    1.3 What are the tools in MDB Tools
    MDB Tools includes
    • LibMDB, a library for accessing MDB files.
    • MDB Utilities, a set of command line utilities to extract schema and data.
    • MDBSQL, a SQL engine layered on top of LibMDB.
    • MDB ODBC driver, a ODBC driver - requires unixODBC driver manager.
    • gmdb2, a graphical interface including SQL query tool and file debugger.
    1.4 What license is MDB Tools under
    The libraries in MDB Tools (libmdb, libmdbsql, and libmdbodbc) are licensed under the LGPL. The remainder of the software is license under the GPL.
    1.5 What Jet Databases does MDB Tools support?
    MDB Tools supports Jet version 3.0 and 4.0 databases. It does not, and probably never will support Jet 2.0. I'm looking into adding support for MSDE databases, and if anyone wants to send some sample databases in that format, I'd be very interested.
    1.6 Is there a roadmap?

    Roughly, the plan moving forward looks like this.

    • Add index scan capability to libmdb and the SQL engine with a query plan generator.
    • Add support for adding rows to existing tables and an mdb-import tool.
    • Add full write support to libmdb and libmdbsql.
    • Extract queries, table properties, VBA script, forms.
    • mdb-check database consistency checker and recovery tool.
    • Add joins.
    • Ability to add tables.

    Of course these are my personal goals, and the direction of the project depends on contributors and feature requests from users.

    1.7 How do I install

    Consult the installation guide for details.

    1.8 I've found a bug

    Post it to the sourceforge project page so it gets tracked and send a note to the list so we can work it out. I may request details about or a copy of your database. Any database sent will be kept confidential.

    1.9 How do I help?

    Join the mailing list, it's very low traffic at the time of this writing.

    If you are a programmer, start with the debugger in gmdb2 to get a feel for the database layout. Read the HACKING file included in the distribution.

    We are currently looking for corrupted Access databases to help with developing recovery tools. If you have them, I will even extract the usable data from them for you for free. ;-)

    1.10 What's this postcard thing?
    I, like many free software others, enjoy getting postcards from where users live. If you're a happy MDB Tools user (or even a disgruntled one, doesn't really matter) and want to drop me a postcard with a picture of the place you live, email me for my snail-mail address. Come on, you know you want to!
    1.11 When will MDB Tools support writing?
    Writing to MDB files is a quite a bit more complicated than simply reading. Some preliminary support is available in the CVS version, this includes under-the-covers things like building rows, adding rows to tables, tracing the index chain to the row, and some work on index writes. These are the nuts and bolts of write support; the big thing left is the allocation of new pages and splitting full pages on inserts. When will this be done? I don't commit to timelines, but the next release (0.7) will have some usable, though not complete, write support.
    mdbtools-0.7.1/doc/gmdb2.txt000066400000000000000000000017121222645741400156530ustar00rootroot00000000000000NAME gmdb2 - GNOME UI for MDB Tools SYNOPSIS gmdb2 [database] DESCRIPTION gmdb2 is a GNOME UI for MDB Tools. ENVIRONMENT MDB_JET3_CHARSET Defines the charset of the input JET3 (access 97) file. Default is CP1252. See iconv(1). MDBICONV Defines the output charset. Default is UTF-8. mdbtools must have been compiled with iconv. MDBOPTS semi-column separated list of options: * use_index * no_memo * debug_like * debug_write * debug_usage * debug_ole * debug_row * debug_props * debug_all is a shortcut for all debug_* options SEE ALSO mdb-export(1) mdb-hexdump(1) mdb-prop(1) mdb-sql(1) mdb-ver(1) mdb-array(1) mdb-header(1) mdb-parsecsv(1) mdb-schema(1) mdb-tables(1) AUTHORS The gmdb2 utility was written by Brian Bruns. mdbtools-0.7.1/doc/install.sgml000066400000000000000000001157271222645741400164650ustar00rootroot00000000000000 $Date: 2005/09/07 23:27:43 $ $Revision: 1.7 $ <productname>MDB Tools</productname> Installation Guide A Guide to Installing and Configuring MDB Tools Brian Bruns 2003 Brian Bruns Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the license is included in the section entitled GNU Free Documentation License. About this Guide This guide is intended to provide help with installing and configuring the MDB Tools suite of programs. It is a work in progress and the author will happily accept new material, clarifications, or other enhancements in any format. Patches to the original DocBook format can be uploaded to the SourceForge patch area under the MDB Tools project page. Changes in plain text and other formats can be submitted directly to the mailing list or the author. A few technical notes. This guide is written in SGML DocBook format, specifications for which are found in the DocBook book. It was converted to HTML with OpenJade. The document you are reading is version $Revision: 1.7 $ , dated $Date: 2005/09/07 23:27:43 $ (CVS control number $Id: install.sgml,v 1.7 2005/09/07 23:27:43 brianb Exp $). The most recent version can be found on the MDB Tools web site. What is <productname>MDB Tools</productname>? MDB Tools is a suite of libraries and programs to facilitate the use of Microsoft Access databases, also known as Jet databases after the Microsoft's Jet Database Engine or as MDB databases after the .mdb extension used by the file containing the database. MDB Toolsis open source software (also known as free software if you prefer) which means source code is provided under a license which allows you as a user to modify and redistribute the software. In particular, the libraries that come with MDB Tools are licensed under the Gnu LGPL (Lesser General Public License) and the utility programs, graphical interface, and miscellania are licensed under the Gnu GPL (General Public License). More information about these licenses can be found in the COPYING.LIB and COPYING files distributed with MDB Tools or from the Gnu site. Components of the <productname>MDB Tools</productname> Suite MDB Tools is composed of three libraries, a set of command line utilities and a graphical interface. LibMDB libmdb is the lowest level library. It handles the details of reading from and writing to the MDB file format. Atop this library sits all the other functionality of MDB Tools. A complete description of libmdb will be available in the forthcoming MDB Tools Programmer's Guide. For now you can look at the utility programs for a general idea of how to use the API, it's fairly straightforward. Command Line Utilities MDB Tools comes with a set of command line utilties that allow mdb files to be used in shell scripting, extraction to another database, and similar functions. Each program is documented in its man page. A brief synopsis follows. MDB Utilities Name Description mdb-tables list tables in the specified file mdb-schema generate schema DDL for the specified file mdb-export generate CSV style output for a table mdb-ver display the version of the specified file mdb-header support for using MDB data in C mdb-parsecsv support for using MDB data in C mdb-sql command line SQL query tool
    LibMDBSQL (the SQL Engine) LibMDBSQL is an SQL engine which provides a subset of the SQL query language to access MDB databases. It is used with the ODBC driver, by the mdb-sql utility, and by the query window in gmdb2. For a description of the supported SQL, see the mdb-sql man page. LibMDBODBC LibMDBODBC is an ODBC driver that works with the unixODBC driver manager to allow MDB Tools to work with such programs as PHP and Perl (via DBD::ODBC). At the time of this writing, the breadth of coverage for the driver is rather limited. If you have specific problems with it, please contact the list and they can most likely be resolved. The ODBC driver relies on LibMDB and LibMDBSQL. Gmdb2 Gmdb2 is a graphical interface to the functionality of MDB Tools. Its interface resembles that of access with a tabbed interface to each of the object types in the database (tables, queries, forms, etc...). Additonally, it sports an SQL Query window, and a file debugger useful for developers or anybody interested in examining the dark secrets of the MDB file format. For information on how to use gmdb2, see the manual under the Help menu.
    Requirements MDB Tools like most packages has some requirements for libraries and such on your system. Most of them are optional and will turn off certain features if not present. Requirements Matrix The following matrix lists all requirements and which features they affect. An X in the major feature categories (SQL, ODBC, gmdb2) means these features will be turned off if the prequisite is not found. Prerequisites Name SQL ODBC gmdb2 Source Notes glib 2.0 X X X www.gtk.org Absolutely required, will not install without readline http://cnswww.cns.cwru.edu/~chet/readline/rltop.html Supports history in mdb-sql, will compile without history if not found. bison/yacc X X www.gnu.org gmdb2 will not have a SQL window and mdb-sql will be stubbed out. flex X X www.gnu.org gmdb2 will not have a SQL window and mdb-sql will be stubbed out. unixODBC X www.unixodbc.com Gnome 2.0 X www.gnome.org libglade X www.gnome.org wordexp Part of the OS, without it ~ expansion in SQL engine will be disabled
    Installation Options MDB Tools call be installed from binaries or by compiling the source package. RPMs RPMs are made available for major releases (not including pre-release or release candidates). The RPM packages are split up along feature boundaries with a core package, a development package, an ODBC package, and a graphical package. To install, simply log in as root and run the following. $ rpm -i mdbtools-0.5-1.rpm $ rpm -i mdbtools-devel-0.5-1.rpm $ rpm -i mdbtools-odbc-0.5-1.rpm $ rpm -i mdbtools-gui-0.5-1.rpm Other Binary Packages Packages for other systems (debian, bsd ports, etc...) may be available, check with your OS vendor. Source If none of the binary options are available to you, or if you prefer, you can configure and compile from the source packages. The next chapter will demonstrate that. Installing from Source There are three basic steps to installing from source configuring building installing Configuring from the tarball If you are installing a release or snapshot tarball follow these steps. These steps assume the tarballs name is mdbtools-0.5.tgz. $ zcat mdbtools-0.5.tgz | tar xvf - $ cd mdbtools-0.5 $ ./configure If you want to include ODBC support, use the --with-unixodbc argument with the location you installed it to (/usr/local by default). $ zcat mdbtools-0.5.tgz | tar xvf - $ cd mdbtools-0.5 $ ./configure --with-unixodbc=/usr/local Configuring from CVS If you are looking for the very latest code you can check out it out of CVS and compile. The configure step uses the autogen.sh script so it's a bit different. $ cvs -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/mdbtools login $ cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/mdbtools co $ cd mdbtools $ ./autogen.sh --with-unixodbc=/usr/local Again, if you don't want ODBC support remove the --with-unixodbc flag. Building Once you are finished configuring simply type make to build. $ make Installing To install, sign in as root and type make install $ su - # make install Post Install Configuration There are a couple of things that can be configured in the package. MDBPATH If you store your MDB files together in directories you can use the MDBPATH environment variable to have MDB Tools search the path similiar to PATH, MANPATH, LD_LIBRARY_PATH (or LIBPATH), etc... Like those, the : (colon) is used as a separator. If you run sh, ksh, or bash $ MDBPATH=/home/myuser/mdbfiles:/data/mdbfiles ; export MDBPATH If you run csh or tcsh $ setenv MDBPATH /home/myuser/mdbfiles:/data/mdbfiles This will cause MDB Tools to first attempt to open the file using the filename or path provided (current directory or absolute path), then to walk through each entry in the MDBPATH file looking for it. It will stop at the first match. The MDBPATH variable affects all utilities and any program calling mdb_open(). Character set encoding Jet 4 databases are encoded using UCS2-LE (Unicode 2 byte little endian) encoding. MDB Tools will convert these values using the "iconv" standard to UTF-8 by default. If your terminal or other output uses an encoding other than UTF-8 you can override the default behaviour by setting the MDBICONV to the desired character set. For sh, ksh, or bash $ MDBICONV=ISO_8859-1 ; export MDBICONV Or for csh or tcsh $ setenv MDBICONV ISO_8859-1 To view a list of possible character sets, you can run the iconv --list command on most Linux systems. Otherwise, consult your vendors documentation. Jet 3 databases use the character set of the machine on which they were created. For US-English systems this will be cp1252 which is assumed by MDB Tools as the default. To use a file generated with another version of Access, set the MDB_JET3_CHARSET environment variable. ODBC In order to use ODBC you must place an entry in the odbcinst.ini file. <filename>odbcinst.ini</filename> file [MDBTools] Description = MDBTools Driver Driver = /usr/local/lib/libmdbodbc.so Setup = /usr/local/lib/libmdbodbc.so FileUsage = 1 You will also need an entry in odbc.ini for each DSN. <filename>odbc.ini</filename> file [Northwind] Description = Northwind Sample Database Driver = MDBTools Database = /data/mdbfiles/Northwind.mdb Consult the unixODBC documentation for full details. GNU Free Documentation License Version 1.1, March 2000 PREAMBLE The purpose of this License is to make a manual, textbook, or other written document "free" in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others. This License is a kind of "copyleft", which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software. We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference. APPLICABILITY AND DEFINITIONS This License applies to any manual or other work that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. The "Document", below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as "you". A "Modified Version" of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language. A "Secondary Section" is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (For example, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them. The "Invariant Sections" are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. The "Cover Texts" are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A "Transparent" copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, whose contents can be viewed and edited directly and straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup has been designed to thwart or discourage subsequent modification by readers is not Transparent. A copy that is not "Transparent" is called "Opaque". Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML designed for human modification. Opaque formats include PostScript, PDF, proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML produced by some word processors for output purposes only. The "Title Page" means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, "Title Page" means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text. VERBATIM COPYING You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3. You may also lend copies, under the same conditions stated above, and you may publicly display copies. COPYING IN QUANTITY If you publish printed copies of the Document numbering more than 100, and the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects. If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages. If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a publicly-accessible computer-network location containing a complete Transparent copy of the Document, free of added material, which the general network-using public has access to download anonymously at no charge using public-standard network protocols. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public. It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document. MODIFICATIONS You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version: Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission. List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has less than five). State on the Title page the name of the publisher of the Modified Version, as the publisher. Preserve all the copyright notices of the Document. Add an appropriate copyright notice for your modifications adjacent to the other copyright notices. Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below. Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice. Include an unaltered copy of this License. Preserve the section entitled "History", and its title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section entitled "History" in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence. Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the "History" section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission. In any section entitled "Acknowledgements" or "Dedications", preserve the section's title, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein. Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles. Delete any section entitled "Endorsements". Such a section may not be included in the Modified Version. Do not retitle any existing section as "Endorsements" or to conflict in title with any Invariant Section. If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles. You may add a section entitled "Endorsements", provided it contains nothing but endorsements of your Modified Version by various parties--for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard. You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one. The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version. COMBINING DOCUMENTS You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice. The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work. In the combination, you must combine any sections entitled "History" in the various original documents, forming one section entitled "History"; likewise combine any sections entitled "Acknowledgements", and any sections entitled "Dedications". You must delete all sections entitled "Endorsements." COLLECTIONS OF DOCUMENTS You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects. You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document. AGGREGATION WITH INDEPENDENT WORKS A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, does not as a whole count as a Modified Version of the Document, provided no compilation copyright is claimed for the compilation. Such a compilation is called an "aggregate", and this License does not apply to the other self-contained works thus compiled with the Document, on account of their being thus compiled, if they are not themselves derivative works of the Document. If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one quarter of the entire aggregate, the Document's Cover Texts may be placed on covers that surround only the Document within the aggregate. Otherwise they must appear on covers around the whole aggregate. TRANSLATION Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License provided that you also include the original English version of this License. In case of a disagreement between the translation and the original English version of this License, the original English version will prevail. TERMINATION You may not copy, modify, sublicense, or distribute the Document except as expressly provided for under this License. Any other attempt to copy, modify, sublicense or distribute the Document 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. FUTURE REVISIONS OF THIS LICENSE The Free Software Foundation may publish new, revised versions of the GNU Free Documentation 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. See http://www.gnu.org/copyleft/. Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License "or any later version" applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. How to use this License for your documents To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page: If you have no Invariant Sections, write "with no Invariant Sections" instead of saying which ones are invariant. If you have no Front-Cover Texts, write "no Front-Cover Texts" instead of "Front-Cover Texts being LIST"; likewise for Back-Cover Texts. If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software.
    mdbtools-0.7.1/doc/mdb-array.txt000066400000000000000000000022011222645741400165300ustar00rootroot00000000000000NAME mdb-array - Export data in an MDB database table to a C array. SYNOPSIS mdb-array database table DESCRIPTION mdb-array is a utility program distributed with MDB Tools. mdb-array prints a C source code file to stdout, containing an array representing the data of the specified table. ENVIRONMENT MDB_JET3_CHARSET Defines the charset of the input JET3 (access 97) file. Default is CP1252. See iconv(1). MDBICONV Defines the output charset. Default is UTF-8. mdbtools must have been compiled with iconv. MDBOPTS semi-column separated list of options: * use_index * no_memo * debug_like * debug_write * debug_usage * debug_ole * debug_row * debug_props * debug_all is a shortcut for all debug_* options SEE ALSO gmdb2(1) mdb-export(1) mdb-hexdump(1) mdb-prop(1) mdb-sql(1) mdb-ver(1) mdb-header(1) mdb-parsecsv(1) mdb-schema(1) mdb-tables(1) AUTHORS The mdb-array utility was written by Brian Bruns. mdbtools-0.7.1/doc/mdb-export.txt000066400000000000000000000046661222645741400167540ustar00rootroot00000000000000NAME mdb-export - Export data in an MDB database table to CSV format. SYNOPSIS mdb-export [-H] [-d delimiter] [-R row_delim] [[-Q] | [-q quote [-X escape]]] [-I backend] [-D format] [-N namespace] [-b strip|raw|octal] database table DESCRIPTION mdb-export is a utility program distributed with MDB Tools. It produces a CSV (comma separated value) output for the given table. Such output is suitable for importation into databases or spreadsheets. OPTIONS -H Supress header row -Q Don't wrap text-like fields (text, memo, date) in quotes. If not specified text fiels will be surrounded by " (double quote) characters. -d Specify an alternative column delimiter If no delimiter is specified, table names will be delimited by a , (comma) character. -R Specify a row delimiter -I backend INSERT statements (instead of CSV). You must specify which SQL backend dialect to use. Allowed values are: access, sybase, oracle, postgres, mysql and sqlite. -D Set the date format (see strftime(3) for details) -q Use to wrap text-like fields. Default is ". -X Use to escape quoted characters within a field. Default is doubling. -N namespace Prefix identifiers with namespace. -b strip|raw|octal Binary export mode: strip binaries, export as-is, or output \ooo style octal data. NOTES ENVIRONMENT MDB_JET3_CHARSET Defines the charset of the input JET3 (access 97) file. Default is CP1252. See iconv(1). MDBICONV Defines the output charset to use for the SQL file. Default is UTF-8. mdbtools must have been compiled with iconv. MDBOPTS semi-column separated list of options: * use_index * no_memo * debug_like * debug_write * debug_usage * debug_ole * debug_row * debug_props * debug_all is a shortcut for all debug_* options SEE ALSO gmdb2(1) mdb-hexdump(1) mdb-prop(1) mdb-sql(1) mdb-ver(1) mdb-array(1) mdb-header(1) mdb-parsecsv(1) mdb-schema(1) mdb-tables(1) HISTORY mdb-export first appeared in MDB Tools 0.1. AUTHORS The mdb-export utility was written by Brian Bruns. BUGS Memo fields are allowed to contain a newline characters, the current program does nothing about this. mdbtools-0.7.1/doc/mdb-header.txt000066400000000000000000000024451222645741400166540ustar00rootroot00000000000000NAME mdb-header - Write header file from an MDB database SYNOPSIS mdb-header [database] DESCRIPTION mdb-header is a utility program distributed with MDB Tools. It will dump the names and types of the tables and columns in an MDB database in a C header format. It will create three files - types.h and dumptypes.[ch] ENVIRONMENT MDB_JET3_CHARSET Defines the charset of the input JET3 (access 97) file. Default is CP1252. See iconv(1). MDBICONV Defines the output charset. Default is UTF-8. mdbtools must have been compiled with iconv. MDBOPTS semi-column separated list of options: * use_index * no_memo * debug_like * debug_write * debug_usage * debug_ole * debug_row * debug_props * debug_all is a shortcut for all debug_* options EXIT STATUS mdb-header exits with error code 1 if there was anunsupported type. SEE ALSO gmdb2(1) mdb-export(1) mdb-hexdump(1) mdb-prop(1) mdb-sql(1) mdb-ver(1) mdb-array(1) mdb-parsecsv(1) mdb-schema(1) mdb-tables(1) AUTHORS The mdb-header utility was written by Brian Bruns. BUGS Only a few types are currently supported. mdbtools-0.7.1/doc/mdb-hexdump.txt000066400000000000000000000021061222645741400170700ustar00rootroot00000000000000NAME mdb-hexdump - Hexdump utility from MDB Tools SYNOPSIS mdb-hexdump file [pagenumber] DESCRIPTION mdb-hexdump is a utility program distributed with MDB Tools. mdb-hexdump makes a hex dump of a binary file (such as an mdb file). ENVIRONMENT MDB_JET3_CHARSET Defines the charset of the input JET3 (access 97) file. Default is CP1252. See iconv(1). MDBICONV Defines the output charset. Default is UTF-8. mdbtools must have been compiled with iconv. MDBOPTS semi-column separated list of options: * use_index * no_memo * debug_like * debug_write * debug_usage * debug_ole * debug_row * debug_props * debug_all is a shortcut for all debug_* options SEE ALSO gmdb2(1) mdb-export(1) mdb-prop(1) mdb-sql(1) mdb-ver(1) mdb-array(1) mdb-header(1) mdb-parsecsv(1) mdb-schema(1) mdb-tables(1) AUTHORS The mdb-hexdump utility was written by Brian Bruns. mdbtools-0.7.1/doc/mdb-parsecsv.txt000066400000000000000000000025251222645741400172510ustar00rootroot00000000000000NAME mdb-parsecsv - Convert CSV table dump into C file. SYNOPSIS mdb-parsecsv file DESCRIPTION mdb-parsecsv is a utility program distributed with MDB Tools. mdb-parsecsv takes a CSV file representing a database table, and converts it into a C array. NOTES If the first argument does not exist as a file, mdb-parsecsv will look for the same filename with '.txt' appended. The file extension is stripped, and the output written to the base name plus a '.c' extension. ENVIRONMENT MDB_JET3_CHARSET Defines the charset of the input JET3 (access 97) file. Default is CP1252. See iconv(1). MDBICONV Defines the output charset to use for the SQL file. Default is UTF-8. mdbtools must have been compiled with iconv. MDBOPTS semi-column separated list of options: * use_index * no_memo * debug_like * debug_write * debug_usage * debug_ole * debug_row * debug_props * debug_all is a shortcut for all debug_* options SEE ALSO gmdb2(1) mdb-export(1) mdb-hexdump(1) mdb-prop(1) mdb-sql(1) mdb-ver(1) mdb-array(1) mdb-header(1) mdb-schema(1) mdb-tables(1) AUTHORS The mdb-parsecsv utility was written by Brian Bruns. mdbtools-0.7.1/doc/mdb-prop.txt000066400000000000000000000023331222645741400164000ustar00rootroot00000000000000NAME mdb-prop - Get properties list from MDB database SYNOPSIS mdb-prop database name [propcol] DESCRIPTION mdb-prop is a utility program distributed with MDB Tools. Print a properties list from an MDB database. name is the name of the table, querry, or other object. propcol is the name of the system table MSysObjects' column containing properties. It defaults to LvProp. ENVIRONMENT MDB_JET3_CHARSET Defines the charset of the input JET3 (access 97) file. Default is CP1252. See iconv(1). MDBICONV Defines the output charset. Default is UTF-8. mdbtools must have been compiled with iconv. MDBOPTS semi-column separated list of options: * use_index * no_memo * debug_like * debug_write * debug_usage * debug_ole * debug_row * debug_props * debug_all is a shortcut for all debug_* options SEE ALSO gmdb2(1) mdb-export(1) mdb-hexdump(1) mdb-sql(1) mdb-ver(1) mdb-array(1) mdb-header(1) mdb-parsecsv(1) mdb-schema(1) mdb-tables(1) AUTHORS The mdb-prop utility was written by Brian Bruns. mdbtools-0.7.1/doc/mdb-schema.txt000066400000000000000000000050601222645741400166600ustar00rootroot00000000000000NAME mdb-schema - Generate schema creation DDL SYNOPSIS mdb-schema [options] database [backend] DESCRIPTION mdb-schema is a utility program distributed with MDB Tools. It produces DDL (data definition language) output for the given database. This can be passed to another database to create a replica of the original access table format. OPTIONS -T , --table
    Single table option. Create schema for this table only. Default is to export all tables. -N namespace Prefix identifiers with namespace. --drop-table Issue DROP TABLE statement. --no-drop-table Don't issue DROP TABLE statement. This is the default. --not-null Issue NOT NULL constraints. This is the default. --no-not-null Don't issue NOT NULL constraints. --default-values Issue DEFAULT values. --no-default-values Don't issue DEFAULT values. This is the default. --not-empty Issue CHECK <> '' constraints. --no-not-empty Don't issue CHECK <> '' constraints. This is the default. --indexes Export INDEXes. This is the default. --no-indexes Don't export INDEXes. --relations Export foreign keys constraints. This is the default. --no-relations Don't export foreign keys constraints. backend Specifies target DDL dialect. Supported values are access, sybase, oracle, postgres, mysql and sqlite. If not specified the generated DDL will be in access format. ENVIRONMENT MDB_JET3_CHARSET Defines the charset of the input JET3 (access 97) file. Default is CP1252. See iconv(1). MDBICONV Defines the output charset to use for the SQL file. Default is UTF-8. mdbtools must have been compiled with iconv. MDBOPTS semi-column separated list of options: * use_index * no_memo * debug_like * debug_write * debug_usage * debug_ole * debug_row * debug_props * debug_all is a shortcut for all debug_* options NOTES HISTORY mdb-schema first appeared in MDB Tools 0.1. SEE ALSO gmdb2(1) mdb-export(1) mdb-hexdump(1) mdb-prop(1) mdb-sql(1) mdb-ver(1) mdb-array(1) mdb-header(1) mdb-parsecsv(1) mdb-tables(1) AUTHORS The mdb-schema utility was written by Brian Bruns and others. BUGS Relationships and other features may not be supported by all databases. Access datatypes are mapped to their closest counterparts in the target backend. This may not always yield an exact fit. mdbtools-0.7.1/doc/mdb-sql.txt000066400000000000000000000067321222645741400162260ustar00rootroot00000000000000NAME mdb-sql - SQL interface to MDB Tools SYNOPSIS mdb-sql [-HFp] [-d delimiter] [-i file] [-o file] [database] DESCRIPTION mdb-sql is a utility program distributed with MDB Tools. mdb-sql allows querying of an MDB database using a limited SQL subset language. OPTIONS -H Supress header row. -F Supress footer row. -p Turn off pretty printing. By default results are printed in an ascii table format which looks nice but is not conducive to manipulating the output with unix tools. This option prints output plainly in a tab separated format. -d Specify an alternative column delimiter. If no delimiter is specified, columns will be delimited by a tab character if pretty printing (-p) is turned off. If pretty printing is enabled this option is meaningless. -i Specify an input file. This option allows an input file containing the SQL to be passed to mdb-sql. See Notes. -o Specify an output file. This option allows the name of an output file to be used instead of stdout. COMMANDS mdb-sql in interactive mode takes some special commands. connect to If no database was specified on the command line this command is necessary before any querys are issued. It also allows the switching of databases once in the tool. disconnect Will disconnect from the current database. go Each batch is sent to the parser using the 'go' command. reset A batch can be cleared using the 'reset' command. list tables The list tables command will display a list of available tables in this database, similar to the mdb-tables utility on the command line. describe table
    Will display the column information for the specified table. quit Will exit the tool. SQL LANGUAGE The currently implemented SQL subset is quite small, supporting only single table queries, no aggregates, and limited support for WHERE clauses. Here is a brief synopsis of the supported language. select: SELECT [* | ] FROM
    WHERE column list: [, ] where clause: [AND ] operator: =, =>, =<, <>, like, <, > literal: integers, floating point numbers, or string literal in single quotes NOTES When passing a file (-i) or piping output to mdb-sql the final 'go' is optional. This allow constructs like echo "Select * from Table1" | mdb-sql mydb.mdb to work correctly. The -i command can be passed the string 'stdin' to test entering text as if using a pipe. ENVIRONMENT MDB_JET3_CHARSET Defines the charset of the input JET3 (access 97) file. Default is CP1252. See iconv(1). MDBICONV Defines the output charset. Default is UTF-8. mdbtools must have been compiled with iconv. MDBOPTS semi-column separated list of options: * use_index * no_memo * debug_like * debug_write * debug_usage * debug_ole * debug_row * debug_props * debug_all is a shortcut for all debug_* options HISTORY mdb-sql first appeared in MDB Tools 0.3. SEE ALSO gmdb2(1) mdb-export(1) mdb-hexdump(1) mdb-prop(1) mdb-ver(1) mdb-array(1) mdb-header(1) mdb-parsecsv(1) mdb-schema(1) mdb-tables(1) isql(1) AUTHORS The mdb-sql utility was written by Brian Bruns. BUGS The supported SQL syntax is a very limited subset and deficient in several ways. mdbtools-0.7.1/doc/mdb-tables.txt000066400000000000000000000033451222645741400166760ustar00rootroot00000000000000NAME mdb-tables - Get listing of tables in an MDB database SYNOPSIS mdb-tables [-S] [-1 | -d delimiter] database DESCRIPTION mdb-tables is a utility program distributed with MDB Tools. It produces a list of tables contained within an MDB database in a format suitable for use in shell scripts. OPTIONS -S Show system tables. System tables are generally those beginning with 'MSys' -1 specifies that the tables should be listed 1 per line. -d delimiter specifies an alternative delimiter. If no delimiter is specified, table names will be delimited by a tab character, or by newline if the -1 option was specified. NOTES ENVIRONMENT MDB_JET3_CHARSET Defines the charset of the input JET3 (access 97) file. Default is CP1252. See iconv(1). MDBICONV Defines the output charset. Default is UTF-8. mdbtools must have been compiled with iconv. MDBOPTS semi-column separated list of options: * use_index * no_memo * debug_like * debug_write * debug_usage * debug_ole * debug_row * debug_props * debug_all is a shortcut for all debug_* options HISTORY mdb-tables first appeared in MDB Tools 0.3. SEE ALSO gmdb2(1) mdb-export(1) mdb-hexdump(1) mdb-prop(1) mdb-sql(1) mdb-ver(1) mdb-array(1) mdb-header(1) mdb-parsecsv(1) mdb-schema(1) AUTHORS The mdb-tables utility was written by Brian Bruns. BUGS Access allows for tables to have spaces embeded in the table name. You must specify a delimiter (-d) if you intend on piping the output of mdb-tables to a program such as awk or cut. mdbtools-0.7.1/doc/mdb-ver.txt000066400000000000000000000035031222645741400162140ustar00rootroot00000000000000NAME mdb-ver - Return the format of a given MDB database. SYNOPSIS mdb-ver database mdb-ver -M DESCRIPTION mdb-ver is a utility program distributed with MDB Tools. It will return a single line of output with 'JET3' for those files produced in Access 97 format, 'JET4' for those produced by Access 2000, XP and 2003, 'ACE12' for those produced by Access 2007, or 'ACE14' for those produced by Access 2010. OPTIONS -M Prints the version of MDB Tools itself instead of the MDB file. NOTES Access changed its format between Jet 3 used in Access 97 and Jet 4 used for Access 2000 and XP. The nature of the changes included moving the page size from 2K to 4K and added support for unicode. MDB Tools actively supports both formats. Newer version are very much like Jet4. ENVIRONMENT MDB_JET3_CHARSET Defines the charset of the input JET3 (access 97) file. Default is CP1252. See iconv(1). MDBICONV Defines the output charset. Default is UTF-8. mdbtools must have been compiled with iconv. MDBOPTS semi-column separated list of options: * use_index * no_memo * debug_like * debug_write * debug_usage * debug_ole * debug_row * debug_props * debug_all is a shortcut for all debug_* options HISTORY mdb-ver first appeared in MDB Tools 0.4. SEE ALSO gmdb2(1) mdb-export(1) mdb-hexdump(1) mdb-prop(1) mdb-sql(1) mdb-array(1) mdb-header(1) mdb-parsecsv(1) mdb-schema(1) mdb-tables(1) AUTHORS The mdb-ver utility was written by Brian Bruns. BUGS mdb-ver does minimal checking on the validity of a file. It is possbile for it to misidentify a non-MDB file. mdb-ver does not recognize Access 2.0 (Jet 2). mdbtools-0.7.1/doc/reference/000077500000000000000000000000001222645741400160545ustar00rootroot00000000000000mdbtools-0.7.1/doc/reference/libmdb/000077500000000000000000000000001222645741400173055ustar00rootroot00000000000000mdbtools-0.7.1/doc/reference/libmdb/Makefile.am000066400000000000000000000130151222645741400213410ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in # This is a blank Makefile.am for using gtk-doc. # Copy this to your project's API docs directory and modify the variables to # suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples # of using the various options. # The name of the module, e.g. 'glib'. DOC_MODULE=libmdb # The top-level SGML file. Change it if you want. DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml # The directory containing the source code. Relative to $(srcdir). # gtk-doc will search all .c & .h files beneath here for inline comments # documenting functions and macros. DOC_SOURCE_DIR=$(top_srcdir)/src/libmdb DOC_HEADER_DIR=$(top_srcdir)/include # Extra options to pass to gtkdoc-scanobj or gtkdoc-scangobj. SCANOBJ_OPTIONS= # Extra options to supply to gtkdoc-scan. SCAN_OPTIONS= # Extra options to supply to gtkdoc-mkdb. MKDB_OPTIONS= # Extra options to supply to gtkdoc-fixref. FIXXREF_OPTIONS= # Used for dependencies. HFILE_GLOB= CFILE_GLOB= # Header files to ignore when scanning. IGNORE_HFILES= # Images to copy into HTML directory. HTML_IMAGES = # Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). content_files = # Other files to distribute. extra_files = # CFLAGS and LDFLAGS for compiling scan program. Only needed if your app/lib # contains GtkObjects/GObjects and you want to document signals and properties. GTKDOC_CFLAGS = GTKDOC_LIBS = GTKDOC_CC=$(LIBTOOL) --mode=compile $(CC) GTKDOC_LD=$(LIBTOOL) --mode=link $(CC) # If you need to override some of the declarations, place them in the # $(DOC_MODULE)-overrides.txt file and uncomment the second line here. DOC_OVERRIDES = #DOC_OVERRIDES = $(DOC_MODULE)-overrides.txt ########################################################################### # Everything below here is generic and you shouldn't need to change it. ########################################################################### TARGET_DIR=$(HTML_DIR)/$(DOC_MODULE) EXTRA_DIST = \ $(content_files) \ $(extra_files) \ $(HTML_IMAGES) \ $(DOC_MAIN_SGML_FILE) \ $(DOC_MODULE).types \ $(DOC_MODULE)-sections.txt \ $(DOC_OVERRIDES) DOC_STAMPS=scan-build.stamp tmpl-build.stamp sgml-build.stamp html-build.stamp \ $(srcdir)/tmpl.stamp $(srcdir)/sgml.stamp $(srcdir)/html.stamp SCANOBJ_FILES = \ $(DOC_MODULE).args \ $(DOC_MODULE).hierarchy \ $(DOC_MODULE).interfaces \ $(DOC_MODULE).prerequisites \ $(DOC_MODULE).signals if ENABLE_GTK_DOC all-local: html-build.stamp #### scan #### scan-build.stamp: $(HFILE_GLOB) @echo '*** Scanning header files ***' if grep -l '^..*$$' $(srcdir)/$(DOC_MODULE).types > /dev/null ; then \ CC="$(GTKDOC_CC)" LD="$(GTKDOC_LD)" CFLAGS="$(GTKDOC_CFLAGS)" LDFLAGS="$(GTKDOC_LIBS)" gtkdoc-scanobj $(SCANOBJ_OPTIONS) --module=$(DOC_MODULE) --output-dir=$(srcdir) ; \ else \ cd $(srcdir) ; \ for i in $(SCANOBJ_FILES) ; do \ test -f $$i || touch $$i ; \ done \ fi cd $(srcdir) && \ gtkdoc-scan --module=$(DOC_MODULE) --source-dir=$(DOC_HEADER_DIR) --source-dir=$(DOC_SOURCE_DIR) --ignore-headers="$(IGNORE_HFILES)" $(SCAN_OPTIONS) $(EXTRA_HFILES) touch scan-build.stamp $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES): scan-build.stamp @true #### templates #### tmpl-build.stamp: $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_OVERRIDES) @echo '*** Rebuilding template files ***' cd $(srcdir) && gtkdoc-mktmpl --module=$(DOC_MODULE) touch tmpl-build.stamp tmpl.stamp: tmpl-build.stamp @true #### sgml #### sgml-build.stamp: tmpl.stamp $(CFILE_GLOB) $(srcdir)/tmpl/*.sgml @echo '*** Building SGML ***' cd $(srcdir) && \ gtkdoc-mkdb --module=$(DOC_MODULE) --source-dir=$(DOC_SOURCE_DIR) --main-sgml-file=$(DOC_MAIN_SGML_FILE) $(MKDB_OPTIONS) touch sgml-build.stamp sgml.stamp: sgml-build.stamp @true #### html #### html-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files) @echo '*** Building HTML ***' test -d $(srcdir)/html || mkdir $(srcdir)/html cd $(srcdir)/html && gtkdoc-mkhtml $(DOC_MODULE) ../$(DOC_MAIN_SGML_FILE) test "x$(HTML_IMAGES)" = "x" || ( cd $(srcdir) && cp $(HTML_IMAGES) html ) @echo '-- Fixing Crossreferences' cd $(srcdir) && gtkdoc-fixxref --module-dir=html --html-dir=$(HTML_DIR) $(FIXXREF_OPTIONS) touch html-build.stamp endif ############## clean-local: rm -f *~ *.bak $(SCANOBJ_FILES) *-unused.txt $(DOC_STAMPS) maintainer-clean-local: clean cd $(srcdir) && rm -rf sgml html $(DOC_MODULE)-decl-list.txt $(DOC_MODULE)-decl.txt install-data-local: $(mkinstalldirs) $(DESTDIR)$(TARGET_DIR) (installfiles=`echo $(srcdir)/html/*.html`; \ if test "$$installfiles" = '$(srcdir)/html/*.html'; \ then echo '-- Nothing to install' ; \ else \ for i in $$installfiles; do \ echo '-- Installing '$$i ; \ $(INSTALL_DATA) $$i $(DESTDIR)$(TARGET_DIR); \ done; \ echo '-- Installing $(srcdir)/html/index.sgml' ; \ $(INSTALL_DATA) $(srcdir)/html/index.sgml $(DESTDIR)$(TARGET_DIR); \ fi) # # Require gtk-doc when making dist # if ENABLE_GTK_DOC dist-check-gtkdoc: else dist-check-gtkdoc: @echo "*** gtk-doc must be installed and enabled in order to make dist" @false endif dist-hook: dist-check-gtkdoc dist-hook-local mkdir $(distdir)/tmpl mkdir $(distdir)/sgml mkdir $(distdir)/html -cp $(srcdir)/tmpl/*.sgml $(distdir)/tmpl -cp $(srcdir)/sgml/*.sgml $(distdir)/sgml -cp $(srcdir)/html/index.sgml $(distdir)/html -cp $(srcdir)/html/*.html $(srcdir)/html/*.css $(distdir)/html images=$(HTML_IMAGES) ; \ for i in $$images ; do \ cp $(srcdir)/$$i $(distdir)/html ; \ done .PHONY : dist-hook-local mdbtools-0.7.1/doc/reference/libmdb/libmdb-docs.sgml000066400000000000000000000004561222645741400223550ustar00rootroot00000000000000 ]> LibMDB Reference Manual LibMDB Function List &libmdb-mdbtools; mdbtools-0.7.1/doc/reference/libmdb/libmdb-sections.txt000066400000000000000000000042601222645741400231260ustar00rootroot00000000000000
    mdbtools MDB_DEBUG MDB_PGSIZE MDB_MAX_OBJ_NAME MDB_MAX_COLS MDB_MAX_IDX_COLS MDB_CATALOG_PG MDB_MEMO_OVERHEAD MDB_BIND_SIZE MdbStrategy mdb_is_logical_op mdb_is_relational_op IS_JET4 IS_JET3 mdb_backends MdbBackendType MdbBackend MdbStatistics MdbFile MdbFormatConstants MdbHandle MdbCatalogEntry MdbProperties MdbColumn mdbsargtree MdbIndexPage MDB_MAX_INDEX_DEPTH MdbIndexChain MdbTableDef MdbColumnProp MdbField MdbSarg mdb_init mdb_open mdb_close mdb_clone_handle mdb_exit mdb_read_catalog mdb_dump_catalog mdb_free_catalog mdb_read_table mdb_rewind_table mdb_table_dump mdb_free_tabledef mdb_read_columns mdb_get_objtype_string mdb_bind_column_by_name mdb_data_dump mdb_bind_column mdb_fetch_row mdb_is_fixed_col mdb_col_to_string mdb_find_end_of_row mdb_col_fixed_size mdb_col_disp_size mdb_ole_read_next mdb_ole_read mdb_set_date_fmt mdb_read_row mdb_get_coltype_string mdb_coltype_takes_length mdb_init_backends mdb_register_backend mdb_remove_backends mdb_set_default_backend mdb_get_relationships mdb_sql_walk_tree mdb_find_indexable_sargs mdb_add_sarg_by_name mdb_read_indices mdb_index_dump mdb_index_scan_free mdb_index_find_next_on_page mdb_index_find_next mdb_index_hash_text mdb_index_scan_init mdb_index_find_row mdb_stats_on mdb_stats_off mdb_dump_stats mdb_like_cmp mdb_crack_row mdb_add_row_to_pg mdb_update_index mdb_pack_row mdb_replace_row mdb_pg_get_freespace mdb_update_row mdb_new_data_pg mdb_map_find_next_freepage mdb_read_props_list mdb_free_props mdb_read_props mdb_create_temp_table mdb_temp_table_add_col mdb_fill_temp_col mdb_fill_temp_field mdb_get_option mdb_debug mdb_unicode2ascii mdb_ascii2unicode mdb_test_string mdb_test_int mdb_add_sarg buffer_dump mdb_read_pg mdb_read_alt_pg mdb_get_byte mdb_get_int16 mdb_get_int32 mdb_get_int32_msb mdb_get_single mdb_get_double mdb_pg_get_byte mdb_pg_get_int16 mdb_pg_get_int32 mdb_pg_get_single mdb_pg_get_double mdb_swap_pgbuf mdb_index_swap_n mdb_test_sargs mdb_test_sarg read_pg_if_16 read_pg_if_32 read_pg_if read_pg_if_n mdb_alloc_tabledef
    mdbtools-0.7.1/include/000077500000000000000000000000001222645741400147745ustar00rootroot00000000000000mdbtools-0.7.1/include/Makefile.am000066400000000000000000000001151222645741400170250ustar00rootroot00000000000000include_HEADERS = mdbtools.h mdbsql.h mdbver.h noinst_HEADERS = mdbprivate.h mdbtools-0.7.1/include/mdbprivate.h000066400000000000000000000021701222645741400173020ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database files * Copyright (C) 2000 Brian Bruns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _mdbprivate_h_ #define _mdbprivate_h_ /* * This header is for stuff lacking a MDB_ or mdb_ something, so they won't be * exported to calling programs. */ #define _(String) (String) #define N_(String) String #define textdomain(Domain) #define bindtextdomain(Package, Directory) #endif mdbtools-0.7.1/include/mdbsql.h000066400000000000000000000064521222645741400164360ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _mdbsql_h_ #define _mdbsql_h_ #ifdef __cplusplus extern "C" { #endif #include #include #include #include typedef struct { MdbHandle *mdb; int all_columns; unsigned int num_columns; GPtrArray *columns; unsigned int num_tables; GPtrArray *tables; MdbTableDef *cur_table; MdbSargNode *sarg_tree; GList *sarg_stack; /* FIX ME */ void *bound_values[256]; unsigned char *kludge_ttable_pg; long max_rows; char error_msg[1024]; } MdbSQL; typedef struct { char *name; int disp_size; void *bind_addr; /* if !NULL then cp parameter to here */ int bind_type; int *bind_len; int bind_max; } MdbSQLColumn; typedef struct { char *name; char *alias; } MdbSQLTable; typedef struct { char *col_name; MdbSarg *sarg; } MdbSQLSarg; extern char *g_input_ptr; #undef YY_INPUT #define YY_INPUT(b, r, ms) (r = mdb_sql_yyinput(b, ms)); #define mdb_sql_has_error(sql) ((sql)->error_msg[0] ? 1 : 0) #define mdb_sql_last_error(sql) ((sql)->error_msg) void mdb_sql_error(MdbSQL* sql, char *fmt, ...); extern MdbSQL *_mdb_sql(MdbSQL *sql); extern MdbSQL *mdb_sql_init(); extern MdbSQLSarg *mdb_sql_alloc_sarg(); extern MdbHandle *mdb_sql_open(MdbSQL *sql, char *db_name); extern int mdb_sql_add_sarg(MdbSQL *sql, char *col_name, int op, char *constant); extern void mdb_sql_all_columns(MdbSQL *sql); extern int mdb_sql_add_column(MdbSQL *sql, char *column_name); extern int mdb_sql_add_table(MdbSQL *sql, char *table_name); extern void mdb_sql_dump(MdbSQL *sql); extern void mdb_sql_exit(MdbSQL *sql); extern void mdb_sql_reset(MdbSQL *sql); extern void mdb_sql_listtables(MdbSQL *sql); extern void mdb_sql_select(MdbSQL *sql); extern void mdb_sql_dump_node(MdbSargNode *node, int level); extern void mdb_sql_close(MdbSQL *sql); extern void mdb_sql_add_or(MdbSQL *sql); extern void mdb_sql_add_and(MdbSQL *sql); extern void mdb_sql_add_not(MdbSQL *sql); extern void mdb_sql_describe_table(MdbSQL *sql); extern MdbSQL* mdb_sql_run_query (MdbSQL*, const gchar*); extern void mdb_sql_set_maxrow(MdbSQL *sql, int maxrow); extern int mdb_sql_eval_expr(MdbSQL *sql, char *const1, int op, char *const2); extern void mdb_sql_bind_all(MdbSQL *sql); extern int mdb_sql_fetch_row(MdbSQL *sql, MdbTableDef *table); extern int mdb_sql_add_temp_col(MdbSQL *sql, MdbTableDef *ttable, int col_num, char *name, int col_type, int col_size, int is_fixed); extern void mdb_sql_bind_column(MdbSQL *sql, int colnum, void *varaddr, int *len_ptr); #ifdef __cplusplus } #endif #endif mdbtools-0.7.1/include/mdbtools.h000066400000000000000000000446071222645741400170030ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database files * Copyright (C) 2000 Brian Bruns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _mdbtools_h_ #define _mdbtools_h_ #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_ICONV #include #endif #ifdef _WIN32 #include #endif #define MDB_DEBUG 0 #define MDB_PGSIZE 4096 //#define MDB_MAX_OBJ_NAME (256*3) /* unicode 16 -> utf-8 worst case */ #define MDB_MAX_OBJ_NAME 256 #define MDB_MAX_COLS 256 #define MDB_MAX_IDX_COLS 10 #define MDB_CATALOG_PG 18 #define MDB_MEMO_OVERHEAD 12 #define MDB_BIND_SIZE 16384 // Theses 2 atrbutes are not supported by all compilers: // M$VC see http://stackoverflow.com/questions/1113409/attribute-constructor-equivalent-in-vc #define MDB_DEPRECATED(type, funcname) type __attribute__((deprecated)) funcname #define MDB_CONSTRUCTOR(funcname) void __attribute__((constructor)) funcname() enum { MDB_PAGE_DB = 0, MDB_PAGE_DATA, MDB_PAGE_TABLE, MDB_PAGE_INDEX, MDB_PAGE_LEAF, MDB_PAGE_MAP }; enum { MDB_VER_JET3 = 0, MDB_VER_JET4 = 1, MDB_VER_ACCDB_2007 = 0x02, MDB_VER_ACCDB_2010 = 0x0103 }; enum { MDB_FORM = 0, MDB_TABLE, MDB_MACRO, MDB_SYSTEM_TABLE, MDB_REPORT, MDB_QUERY, MDB_LINKED_TABLE, MDB_MODULE, MDB_RELATIONSHIP, MDB_UNKNOWN_09, MDB_UNKNOWN_0A, /* User access */ MDB_DATABASE_PROPERTY, MDB_ANY = -1 }; enum { MDB_BOOL = 0x01, MDB_BYTE = 0x02, MDB_INT = 0x03, MDB_LONGINT = 0x04, MDB_MONEY = 0x05, MDB_FLOAT = 0x06, MDB_DOUBLE = 0x07, MDB_DATETIME = 0x08, MDB_BINARY = 0x09, MDB_TEXT = 0x0a, MDB_OLE = 0x0b, MDB_MEMO = 0x0c, MDB_REPID = 0x0f, MDB_NUMERIC = 0x10, MDB_COMPLEX = 0x12 }; /* SARG operators */ enum { MDB_OR = 1, MDB_AND, MDB_NOT, MDB_EQUAL, MDB_GT, MDB_LT, MDB_GTEQ, MDB_LTEQ, MDB_LIKE, MDB_ISNULL, MDB_NOTNULL }; typedef enum { MDB_TABLE_SCAN, MDB_LEAF_SCAN, MDB_INDEX_SCAN } MdbStrategy; typedef enum { MDB_NOFLAGS = 0x00, MDB_WRITABLE = 0x01 } MdbFileFlags; enum { MDB_DEBUG_LIKE = 0x0001, MDB_DEBUG_WRITE = 0x0002, MDB_DEBUG_USAGE = 0x0004, MDB_DEBUG_OLE = 0x0008, MDB_DEBUG_ROW = 0x0010, MDB_DEBUG_PROPS = 0x0020, MDB_USE_INDEX = 0x0040, MDB_NO_MEMO = 0x0080, /* don't follow memo fields */ }; #define mdb_is_logical_op(x) (x == MDB_OR || \ x == MDB_AND || \ x == MDB_NOT ) #define mdb_is_relational_op(x) (x == MDB_EQUAL || \ x == MDB_GT || \ x == MDB_LT || \ x == MDB_GTEQ || \ x == MDB_LTEQ || \ x == MDB_LIKE || \ x == MDB_ISNULL || \ x == MDB_NOTNULL ) enum { MDB_ASC, MDB_DESC }; enum { MDB_IDX_UNIQUE = 0x01, MDB_IDX_IGNORENULLS = 0x02, MDB_IDX_REQUIRED = 0x08 }; /* export schema options */ enum { MDB_SHEXP_DROPTABLE = 1<<0, /* issue drop table during export */ MDB_SHEXP_CST_NOTNULL = 1<<1, /* generate NOT NULL constraints */ MDB_SHEXP_CST_NOTEMPTY = 1<<2, /* <>'' constraints */ MDB_SHEXP_COMMENTS = 1<<3, /* export comments on columns & tables */ MDB_SHEXP_DEFVALUES = 1<<4, /* export default values */ MDB_SHEXP_INDEXES = 1<<5, /* export indices */ MDB_SHEXP_RELATIONS = 1<<6 /* export relation (foreign keys) */ }; #define MDB_SHEXP_DEFAULT (MDB_SHEXP_CST_NOTNULL | MDB_SHEXP_COMMENTS | MDB_SHEXP_INDEXES | MDB_SHEXP_RELATIONS) /* csv export binary options */ enum { MDB_BINEXPORT_STRIP, MDB_BINEXPORT_RAW, MDB_BINEXPORT_OCTAL }; #define IS_JET4(mdb) (mdb->f->jet_version==MDB_VER_JET4) /* obsolete */ #define IS_JET3(mdb) (mdb->f->jet_version==MDB_VER_JET3) /* forward declarations */ typedef struct mdbindex MdbIndex; typedef struct mdbsargtree MdbSargNode; typedef struct { char *name; unsigned char needs_length; /* or precision */ unsigned char needs_scale; unsigned char needs_quotes; } MdbBackendType; typedef struct { guint32 capabilities; /* see MDB_SHEXP_* */ MdbBackendType *types_table; MdbBackendType *type_shortdate; MdbBackendType *type_autonum; const char *short_now; const char *long_now; const char *charset_statement; const char *drop_statement; const char *constaint_not_empty_statement; const char *column_comment_statement; const char *table_comment_statement; gchar* (*quote_schema_name)(const gchar*, const gchar*); } MdbBackend; typedef struct { gboolean collect; unsigned long pg_reads; } MdbStatistics; typedef struct { int fd; gboolean writable; char *filename; guint32 jet_version; guint32 db_key; char db_passwd[14]; MdbBackend *default_backend; char *backend_name; MdbStatistics *stats; /* free map */ int map_sz; unsigned char *free_map; /* reference count */ int refs; } MdbFile; /* offset to row count on data pages...version dependant */ typedef struct { ssize_t pg_size; guint16 row_count_offset; guint16 tab_num_rows_offset; guint16 tab_num_cols_offset; guint16 tab_num_idxs_offset; guint16 tab_num_ridxs_offset; guint16 tab_usage_map_offset; guint16 tab_first_dpg_offset; guint16 tab_cols_start_offset; guint16 tab_ridx_entry_size; guint16 col_flags_offset; guint16 col_size_offset; guint16 col_num_offset; guint16 tab_col_entry_size; guint16 tab_free_map_offset; guint16 tab_col_offset_var; guint16 tab_col_offset_fixed; guint16 tab_row_col_num_offset; } MdbFormatConstants; typedef struct { MdbFile *f; guint32 cur_pg; guint16 row_num; unsigned int cur_pos; unsigned char pg_buf[MDB_PGSIZE]; unsigned char alt_pg_buf[MDB_PGSIZE]; unsigned int num_catalog; GPtrArray *catalog; MdbBackend *default_backend; char *backend_name; MdbFormatConstants *fmt; MdbStatistics *stats; #ifdef HAVE_ICONV iconv_t iconv_in; iconv_t iconv_out; #endif } MdbHandle; typedef struct { MdbHandle *mdb; char object_name[MDB_MAX_OBJ_NAME+1]; int object_type; unsigned long table_pg; /* misnomer since object may not be a table */ //int num_props; please use props->len GArray *props; /* GArray of MdbProperties */ GArray *columns; int flags; } MdbCatalogEntry; typedef struct { gchar *name; GHashTable *hash; } MdbProperties; typedef union { int i; double d; char s[256]; } MdbAny; struct S_MdbTableDef; /* forward definition */ typedef struct { struct S_MdbTableDef *table; char name[MDB_MAX_OBJ_NAME+1]; int col_type; int col_size; void *bind_ptr; int *len_ptr; GHashTable *properties; unsigned int num_sargs; GPtrArray *sargs; GPtrArray *idx_sarg_cache; unsigned char is_fixed; int query_order; /* col_num is the current column order, * does not include deletes */ int col_num; int cur_value_start; int cur_value_len; /* MEMO/OLE readers */ guint32 cur_blob_pg_row; int chunk_size; /* numerics only */ int col_prec; int col_scale; unsigned char is_long_auto; unsigned char is_uuid_auto; MdbProperties *props; /* info needed for handling deleted/added columns */ int fixed_offset; unsigned int var_col_num; /* row_col_num is the row column number order, * including deleted columns */ int row_col_num; } MdbColumn; struct mdbsargtree { int op; MdbColumn *col; MdbAny value; void *parent; MdbSargNode *left; MdbSargNode *right; }; typedef struct { guint32 pg; int start_pos; int offset; int len; guint16 idx_starts[2000]; unsigned char cache_value[256]; } MdbIndexPage; typedef int (*MdbSargTreeFunc)(MdbSargNode *, gpointer data); #define MDB_MAX_INDEX_DEPTH 10 typedef struct { int cur_depth; guint32 last_leaf_found; int clean_up_mode; MdbIndexPage pages[MDB_MAX_INDEX_DEPTH]; } MdbIndexChain; typedef struct S_MdbTableDef { MdbCatalogEntry *entry; char name[MDB_MAX_OBJ_NAME+1]; unsigned int num_cols; GPtrArray *columns; unsigned int num_rows; int index_start; unsigned int num_real_idxs; unsigned int num_idxs; GPtrArray *indices; guint32 first_data_pg; guint32 cur_pg_num; guint32 cur_phys_pg; unsigned int cur_row; int noskip_del; /* don't skip deleted rows */ /* object allocation map */ guint32 map_base_pg; size_t map_sz; unsigned char *usage_map; /* pages with free space left */ guint32 freemap_base_pg; size_t freemap_sz; unsigned char *free_usage_map; /* query planner */ MdbSargNode *sarg_tree; MdbStrategy strategy; MdbIndex *scan_idx; MdbHandle *mdbidx; MdbIndexChain *chain; MdbProperties *props; unsigned int num_var_cols; /* to know if row has variable columns */ /* temp table */ unsigned int is_temp_table; GPtrArray *temp_table_pages; } MdbTableDef; struct mdbindex { int index_num; char name[MDB_MAX_OBJ_NAME+1]; unsigned char index_type; guint32 first_pg; int num_rows; /* number rows in index */ unsigned int num_keys; short key_col_num[MDB_MAX_IDX_COLS]; unsigned char key_col_order[MDB_MAX_IDX_COLS]; unsigned char flags; MdbTableDef *table; }; typedef struct { char name[MDB_MAX_OBJ_NAME+1]; } MdbColumnProp; typedef struct { void *value; int siz; int start; unsigned char is_null; unsigned char is_fixed; int colnum; int offset; } MdbField; typedef struct { int op; MdbAny value; } MdbSarg; /* mem.c */ extern MDB_DEPRECATED(void, mdb_init()); extern MDB_DEPRECATED(void, mdb_exit()); /* file.c */ extern ssize_t mdb_read_pg(MdbHandle *mdb, unsigned long pg); extern ssize_t mdb_read_alt_pg(MdbHandle *mdb, unsigned long pg); extern unsigned char mdb_get_byte(void *buf, int offset); extern int mdb_get_int16(void *buf, int offset); extern long mdb_get_int32(void *buf, int offset); extern long mdb_get_int32_msb(void *buf, int offset); extern float mdb_get_single(void *buf, int offset); extern double mdb_get_double(void *buf, int offset); extern unsigned char mdb_pg_get_byte(MdbHandle *mdb, int offset); extern int mdb_pg_get_int16(MdbHandle *mdb, int offset); extern long mdb_pg_get_int32(MdbHandle *mdb, int offset); extern float mdb_pg_get_single(MdbHandle *mdb, int offset); extern double mdb_pg_get_double(MdbHandle *mdb, int offset); extern MdbHandle *mdb_open(const char *filename, MdbFileFlags flags); extern void mdb_close(MdbHandle *mdb); extern MdbHandle *mdb_clone_handle(MdbHandle *mdb); extern void mdb_swap_pgbuf(MdbHandle *mdb); /* catalog.c */ extern void mdb_free_catalog(MdbHandle *mdb); extern GPtrArray *mdb_read_catalog(MdbHandle *mdb, int obj_type); MdbCatalogEntry *mdb_get_catalogentry_by_name(MdbHandle *mdb, const gchar* name); extern void mdb_dump_catalog(MdbHandle *mdb, int obj_type); extern char *mdb_get_objtype_string(int obj_type); /* table.c */ extern MdbTableDef *mdb_alloc_tabledef(MdbCatalogEntry *entry); extern void mdb_free_tabledef(MdbTableDef *table); extern MdbTableDef *mdb_read_table(MdbCatalogEntry *entry); extern MdbTableDef *mdb_read_table_by_name(MdbHandle *mdb, gchar *table_name, int obj_type); extern void mdb_append_column(GPtrArray *columns, MdbColumn *in_col); extern void mdb_free_columns(GPtrArray *columns); extern GPtrArray *mdb_read_columns(MdbTableDef *table); extern void mdb_table_dump(MdbCatalogEntry *entry); extern guint8 read_pg_if_8(MdbHandle *mdb, int *cur_pos); extern guint16 read_pg_if_16(MdbHandle *mdb, int *cur_pos); extern guint32 read_pg_if_32(MdbHandle *mdb, int *cur_pos); extern void *read_pg_if_n(MdbHandle *mdb, void *buf, int *cur_pos, size_t len); extern int mdb_is_user_table(MdbCatalogEntry *entry); extern int mdb_is_system_table(MdbCatalogEntry *entry); extern const char *mdb_table_get_prop(const MdbTableDef *table, const gchar *key); extern const char *mdb_col_get_prop(const MdbColumn *col, const gchar *key); /* data.c */ extern int mdb_bind_column_by_name(MdbTableDef *table, gchar *col_name, void *bind_ptr, int *len_ptr); extern void mdb_data_dump(MdbTableDef *table); extern void mdb_date_to_tm(double td, struct tm *t); extern void mdb_bind_column(MdbTableDef *table, int col_num, void *bind_ptr, int *len_ptr); extern int mdb_rewind_table(MdbTableDef *table); extern int mdb_fetch_row(MdbTableDef *table); extern int mdb_is_fixed_col(MdbColumn *col); extern char *mdb_col_to_string(MdbHandle *mdb, void *buf, int start, int datatype, int size); extern int mdb_find_pg_row(MdbHandle *mdb, int pg_row, void **buf, int *off, size_t *len); extern int mdb_find_row(MdbHandle *mdb, int row, int *start, size_t *len); extern int mdb_find_end_of_row(MdbHandle *mdb, int row); extern int mdb_col_fixed_size(MdbColumn *col); extern int mdb_col_disp_size(MdbColumn *col); extern size_t mdb_ole_read_next(MdbHandle *mdb, MdbColumn *col, void *ole_ptr); extern size_t mdb_ole_read(MdbHandle *mdb, MdbColumn *col, void *ole_ptr, int chunk_size); extern void* mdb_ole_read_full(MdbHandle *mdb, MdbColumn *col, size_t *size); extern void mdb_set_date_fmt(const char *); extern int mdb_read_row(MdbTableDef *table, unsigned int row); /* dump.c */ extern void mdb_buffer_dump(const void *buf, int start, size_t len); /* backend.c */ extern MDB_DEPRECATED(char*, mdb_get_coltype_string(MdbBackend *backend, int col_type)); extern MDB_DEPRECATED(int, mdb_coltype_takes_length(MdbBackend *backend, int col_type)); extern const MdbBackendType* mdb_get_colbacktype(const MdbColumn *col); extern const char* mdb_get_colbacktype_string(const MdbColumn *col); extern int mdb_colbacktype_takes_length(const MdbColumn *col); extern MDB_DEPRECATED(void, mdb_init_backends()); extern void mdb_register_backend(char *backend_name, guint32 capabilities, MdbBackendType *backend_type, MdbBackendType *type_shortdate, MdbBackendType *type_autonum, const char *short_now, const char *long_now, const char *charset_statement, const char *drop_statement, const char *constaint_not_empty_statement, const char *column_comment_statement, const char *table_comment_statement, gchar* (*quote_schema_name)(const gchar*, const gchar*)); extern MDB_DEPRECATED(void, mdb_remove_backends()); extern int mdb_set_default_backend(MdbHandle *mdb, const char *backend_name); extern void mdb_print_schema(MdbHandle *mdb, FILE *outfile, char *tabname, char *dbnamespace, guint32 export_options); /* sargs.c */ extern int mdb_test_sargs(MdbTableDef *table, MdbField *fields, int num_fields); extern int mdb_test_sarg(MdbHandle *mdb, MdbColumn *col, MdbSargNode *node, MdbField *field); extern void mdb_sql_walk_tree(MdbSargNode *node, MdbSargTreeFunc func, gpointer data); extern int mdb_find_indexable_sargs(MdbSargNode *node, gpointer data); extern int mdb_add_sarg_by_name(MdbTableDef *table, char *colname, MdbSarg *in_sarg); extern int mdb_test_string(MdbSargNode *node, char *s); extern int mdb_test_int(MdbSargNode *node, gint32 i); extern int mdb_add_sarg(MdbColumn *col, MdbSarg *in_sarg); /* index.c */ extern GPtrArray *mdb_read_indices(MdbTableDef *table); extern void mdb_index_dump(MdbTableDef *table, MdbIndex *idx); extern void mdb_index_scan_free(MdbTableDef *table); extern int mdb_index_find_next_on_page(MdbHandle *mdb, MdbIndexPage *ipg); extern int mdb_index_find_next(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain, guint32 *pg, guint16 *row); extern void mdb_index_hash_text(char *text, char *hash); extern void mdb_index_scan_init(MdbHandle *mdb, MdbTableDef *table); extern int mdb_index_find_row(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain, guint32 pg, guint16 row); extern void mdb_index_swap_n(unsigned char *src, int sz, unsigned char *dest); extern void mdb_free_indices(GPtrArray *indices); void mdb_index_page_reset(MdbIndexPage *ipg); extern int mdb_index_pack_bitmap(MdbHandle *mdb, MdbIndexPage *ipg); /* stats.c */ extern void mdb_stats_on(MdbHandle *mdb); extern void mdb_stats_off(MdbHandle *mdb); extern void mdb_dump_stats(MdbHandle *mdb); /* like.c */ extern int mdb_like_cmp(char *s, char *r); /* write.c */ extern void mdb_put_int16(void *buf, guint32 offset, guint32 value); extern void mdb_put_int32(void *buf, guint32 offset, guint32 value); extern void mdb_put_int32_msb(void *buf, guint32 offset, guint32 value); extern int mdb_crack_row(MdbTableDef *table, int row_start, int row_end, MdbField *fields); extern guint16 mdb_add_row_to_pg(MdbTableDef *table, unsigned char *row_buffer, int new_row_size); extern int mdb_update_index(MdbTableDef *table, MdbIndex *idx, unsigned int num_fields, MdbField *fields, guint32 pgnum, guint16 rownum); extern int mdb_insert_row(MdbTableDef *table, int num_fields, MdbField *fields); extern int mdb_pack_row(MdbTableDef *table, unsigned char *row_buffer, unsigned int num_fields, MdbField *fields); extern int mdb_replace_row(MdbTableDef *table, int row, void *new_row, int new_row_size); extern int mdb_pg_get_freespace(MdbHandle *mdb); extern int mdb_update_row(MdbTableDef *table); extern void *mdb_new_data_pg(MdbCatalogEntry *entry); /* map.c */ extern guint32 mdb_map_find_next_freepage(MdbTableDef *table, int row_size); extern gint32 mdb_map_find_next(MdbHandle *mdb, unsigned char *map, unsigned int map_sz, guint32 start_pg); /* props.c */ extern void mdb_free_props(MdbProperties *props); extern void mdb_dump_props(MdbProperties *props, FILE *outfile, int show_name); extern GArray* mdb_kkd_to_props(MdbHandle *mdb, void *kkd, size_t len); /* worktable.c */ extern MdbTableDef *mdb_create_temp_table(MdbHandle *mdb, char *name); extern void mdb_temp_table_add_col(MdbTableDef *table, MdbColumn *col); extern void mdb_fill_temp_col(MdbColumn *tcol, char *col_name, int col_size, int col_type, int is_fixed); extern void mdb_fill_temp_field(MdbField *field, void *value, int siz, int is_fixed, int is_null, int start, int column); extern void mdb_temp_columns_end(MdbTableDef *table); /* options.c */ extern int mdb_get_option(unsigned long optnum); extern void mdb_debug(int klass, char *fmt, ...); /* iconv.c */ extern int mdb_unicode2ascii(MdbHandle *mdb, char *src, size_t slen, char *dest, size_t dlen); extern int mdb_ascii2unicode(MdbHandle *mdb, char *src, size_t slen, char *dest, size_t dlen); extern void mdb_iconv_init(MdbHandle *mdb); extern void mdb_iconv_close(MdbHandle *mdb); extern const char* mdb_target_charset(MdbHandle *mdb); #ifdef __cplusplus } #endif #endif /* _mdbtools_h_ */ mdbtools-0.7.1/include/mdbver.h.in000066400000000000000000000017201222645741400170310ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database files * Copyright (C) 2000 Brian Bruns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _mdbver_h_ #define _mdbver_h_ #define MDB_FULL_VERSION "@PACKAGE@ v@VERSION@" #define MDB_VERSION_NO "@VERSION@" #endif mdbtools-0.7.1/libmdb.pc.in000066400000000000000000000005551222645741400155400ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ # Ideally we should have a versioned library eg. -lmdb-1 # and also a versioned include path eg. -I${includedir}/libmdb-1.0 # for parallel installability. Name: libmdb Description: core MDB file support library Requires: glib-2.0 Version: @VERSION@ Libs: -L${libdir} -lmdb Cflags: mdbtools-0.7.1/libmdbsql.pc.in000066400000000000000000000005541222645741400162570ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ # Ideally we should have a versioned library eg. -lmdb-1 # and also a versioned include path eg. -I${includedir}/libmdb-1.0 # for parallel installability. Name: libmdbsql Description: libmdb based SQL engine Requires: libmdb Version: @VERSION@ Libs: -L${libdir} -lmdbsql Cflags: mdbtools-0.7.1/m4/000077500000000000000000000000001222645741400136715ustar00rootroot00000000000000mdbtools-0.7.1/m4/ccalias.m4000066400000000000000000000012611222645741400155320ustar00rootroot00000000000000dnl Check whether the target supports symbol aliases. dnl This is a mdbtools specific version dnl TODO: Check if gnulib version works, and add serial dnl Code copied from libgomp AC_DEFUN([AM_GCC_ATTRIBUTE_ALIAS], [ AC_CACHE_CHECK([whether the target supports symbol aliases], am_cv_gcc_have_attribute_alias, [ AC_LINK_IFELSE([AC_LANG_PROGRAM([ void foo(void) { } extern void bar(void) __attribute__((alias("foo")));], [bar();])], am_cv_gcc_have_attribute_alias=yes, am_cv_gcc_have_attribute_alias=no)]) if test $am_cv_gcc_have_attribute_alias = yes; then AC_DEFINE(HAVE_ATTRIBUTE_ALIAS, 1, [Define to 1 if the target supports __attribute__((alias(...))).]) fi]) mdbtools-0.7.1/m4/iconv.m4000066400000000000000000000047111222645741400152540ustar00rootroot00000000000000dnl This is a mdbtools specific version of iconv.m4 dnl Do not put a serial in it, or be prepared to install extra stuff like rpath.config dnl dnl From Bruno Haible. AC_DEFUN([AM_ICONV], [ dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and dnl those with the standalone portable GNU libiconv installed). AC_ARG_WITH([libiconv-prefix], AS_HELP_STRING([--with-libiconv-prefix=DIR], [search for libiconv in DIR/include and DIR/lib]), [ for dir in `echo "$withval" | tr : ' '`; do if test -d $dir/include; then CPPFLAGS="$CPPFLAGS -I$dir/include"; fi if test -d $dir/lib; then LDFLAGS="$LDFLAGS -L$dir/lib"; fi done ]) AC_CACHE_CHECK(for iconv, am_cv_func_iconv, [ am_cv_func_iconv="no, consider installing GNU libiconv" am_cv_lib_iconv=no AC_LINK_IFELSE([AC_LANG_PROGRAM([#include #include ], [iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd);])], am_cv_func_iconv=yes) if test "$am_cv_func_iconv" != yes; then am_save_LIBS="$LIBS" LIBS="$LIBS -liconv" AC_LINK_IFELSE([AC_LANG_PROGRAM([#include #include ], [iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd);])], [am_cv_lib_iconv=yes am_cv_func_iconv=yes]) LIBS="$am_save_LIBS" fi ]) if test "$am_cv_func_iconv" = yes; then AC_DEFINE(HAVE_ICONV, 1, [Define if you have the iconv() function.]) AC_MSG_CHECKING([for iconv declaration]) AC_CACHE_VAL(am_cv_proto_iconv, [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #include #include extern #ifdef __cplusplus "C" #endif #if defined(__STDC__) || defined(__cplusplus) size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); #else size_t iconv(); #endif ], [])], [am_cv_proto_iconv_arg1=""], [am_cv_proto_iconv_arg1="const"]) am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"]) am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` AC_MSG_RESULT([$]{ac_t:- }[$]am_cv_proto_iconv) AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1, [Define as const if the declaration of iconv() needs const.]) fi LIBICONV= if test "$am_cv_lib_iconv" = yes; then LIBICONV="-liconv" fi AC_SUBST(LIBICONV) ]) mdbtools-0.7.1/m4/readline.m4000066400000000000000000000027371222645741400157270ustar00rootroot00000000000000dnl readline.m4 dnl mdbtools specific version dnl TODO: Check if official version works then add serial AC_DEFUN([VL_LIB_READLINE], [ AC_CACHE_CHECK([for a readline compatible library], vl_cv_lib_readline, [ ORIG_LIBS="$LIBS" for readline_lib in readline edit editline; do for termcap_lib in "" termcap curses ncurses; do TRY_LIB="-l$readline_lib" if test -n "$termcap_lib"; then TRY_LIB="$TRY_LIB -l$termcap_lib" fi LIBS="$ORIG_LIBS $TRY_LIB" AC_TRY_LINK_FUNC(readline, vl_cv_lib_readline=yes) if test "$vl_cv_lib_readline" = yes; then break fi done if test "$vl_cv_lib_readline" = yes; then break fi done ]) if test "$vl_cv_lib_readline" = yes; then AC_DEFINE(HAVE_LIBREADLINE, 1, [Define if you have a readline compatible library]) AC_CHECK_HEADERS(readline.h readline/readline.h) AC_CACHE_CHECK([whether readline supports history], vl_cv_lib_readline_history, [ AC_TRY_LINK_FUNC(add_history, vl_cv_lib_readline_history=yes) ]) if test "$vl_cv_lib_readline_history" = yes; then AC_DEFINE(HAVE_READLINE_HISTORY, 1, [Define if your readline library has \`add_history']) AC_CHECK_HEADERS(history.h readline/history.h) fi fi LIBS="$ORIG_LIBS" LIBREADLINE= if test "$vl_cv_lib_readline" = yes; then LIBREADLINE="$TRY_LIB" fi AC_SUBST(LIBREADLINE) ])dnl mdbtools-0.7.1/mdbtools.spec.in000066400000000000000000000054131222645741400164600ustar00rootroot00000000000000%define name @PACKAGE@ %define version @VERSION@ Name: %{name} Version: %{version} Release: 1 Vendor: mdbtools.sourceforge.net Copyright: LGPL/GPL Group: System Environment/Libraries Source: http://download.sourceforge.net/mdbtools/%{name}-%{version}.tgz BuildRoot: /var/tmp/%{name}-buildroot Summary: MDB Tools is a suite of libraries and program for accessing data stored in Microsoft Access databases. %description mdb-dump -- simple hex dump utility for looking at mdb files mdb-schema -- prints DDL for the specified table mdb-export -- export table to CSV format mdb-tables -- a simple dump of table names to be used with shell scripts mdb-header -- generates a C header to be used in exporting mdb data to a C prog mdb-parsecvs -- generates a C program given a CSV file made with mdb-export mdb-sql -- demo SQL engine program mdb-ver -- print version of database %package devel Group: Development/Libraries Summary: Include files needed for development with MDB Tools Requires: mdbtools = %{version} %package odbc Group: System Environment/Libraries Summary: MDB Tools ODBC driver for unixODBC Requires: mdbtools = %{version}, unixODBC >= 2.0.0 %package gui Group: Applications/Databases Summary: gmdb2 graphical interface for MDB Tools Requires: mdbtools = %{version}, libgnomeui >= 2.0.0, libglade2 >= 2.0.0 %description devel The mdbtools-devel package contains the files necessary for development with with the MDB Tools libraries. %description odbc The mdbtools-odbc package contains ODBC driver build for unixODBC. %description gui The mdbtools-gui package contains the gmdb2 graphical user interface for MDB Tools %prep %setup %build %configure --with-unixodbc=/usr/local make RPM_OPT_FLAGS="$RPM_OPT_FLAGS" %install rm -rf "$RPM_BUILD_ROOT" make DESTDIR="$RPM_BUILD_ROOT" install gunzip -c doc/install.tgz | tar x %post /sbin/ldconfig %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) %doc AUTHORS BUGS COPYING ChangeLog INSTALL NEWS README TODO HACKING %{_libdir}/libmdb.a %{_libdir}/libmdb.la %{_libdir}/libmdb.so* %{_libdir}/libmdbsql.a %{_libdir}/libmdbsql.la %{_libdir}/libmdbsql.so* %{_bindir}/mdb-schema %{_bindir}/mdb-export %{_bindir}/mdb-tables %{_bindir}/mdb-header %{_bindir}/mdb-parsecsv %{_bindir}/mdb-dump %{_bindir}/mdb-sql %{_bindir}/mdb-ver %{_bindir}/mdb-array %{_mandir}/man1/* %files devel %defattr (-,root,root) %{_includedir}/mdbtools.h %{_includedir}/mdbsql.h %files odbc %defattr(-,root,root) %{_libdir}/libmdbodbc.la %{_libdir}/libmdbodbc.a %{_libdir}/libmdbodbc.so* %files gui %defattr (-,root,root) %{_bindir}/gmdb2 %{_datadir}/gmdb/glade/* %{_datadir}/gnome/help/gmdb/C/* %{_datadir}/gnome/help/gmdb/C/figures/* %changelog * Sat Jan 11 2003 Brian Bruns - Modifications for 0.5 ver and making .in version mdbtools-0.7.1/omf.make000066400000000000000000000045611222645741400147770ustar00rootroot00000000000000# # No modifications of this Makefile should be necessary. # # This file contains the build instructions for installing OMF files. It is # generally called from the makefiles for particular formats of documentation. # # Note that you must configure your package with --localstatedir=/var # so that the scrollkeeper-update command below will update the database # in the standard scrollkeeper directory. # # If it is impossible to configure with --localstatedir=/var, then # modify the definition of scrollkeeper_localstate_dir so that # it points to the correct location. Note that you must still use # $(localstatedir) in this or when people build RPMs it will update # the real database on their system instead of the one under RPM_BUILD_ROOT. # # Note: This make file is not incorporated into xmldocs.make because, in # general, there will be other documents install besides XML documents # and the makefiles for these formats should also include this file. # # About this file: # This file was derived from scrollkeeper_example2, a package # illustrating how to install documentation and OMF files for use with # ScrollKeeper 0.3.x and 0.4.x. For more information, see: # http://scrollkeeper.sourceforge.net/ # Version: 0.1.3 (last updated: March 20, 2002) # omf_dest_dir=$(datadir)/omf/@PACKAGE@ scrollkeeper_localstate_dir = $(localstatedir)/scrollkeeper # At some point, it may be wise to change to something like this: # scrollkeeper_localstate_dir = @SCROLLKEEPER_STATEDIR@ omf: omf_timestamp omf_timestamp: $(omffile) -for file in $(omffile); do \ absfile=$(srcdir)/$$file; \ test -r $$file && absfile=$$file; \ scrollkeeper-preinstall $(docdir)/$(docname).xml $$absfile $$file.out; \ done; \ touch omf_timestamp install-data-hook-omf: $(mkinstalldirs) $(DESTDIR)$(omf_dest_dir) for file in $(omffile); do \ absfile=$(srcdir)/$$file.out; \ test -r $$file.out && absfile=$$file.out; \ $(INSTALL_DATA) $$absfile $(DESTDIR)$(omf_dest_dir)/$$file; \ done -scrollkeeper-update -p $(DESTDIR)$(scrollkeeper_localstate_dir) -o $(DESTDIR)$(omf_dest_dir) uninstall-local-omf: -for file in $(omffile); do \ basefile=`basename $$file`; \ rm -f $(DESTDIR)$(omf_dest_dir)/$$basefile; \ done -rmdir $(DESTDIR)$(omf_dest_dir) -scrollkeeper-update -p $(DESTDIR)$(scrollkeeper_localstate_dir) clean-local-omf: -for file in $(omffile); do \ rm -f $$file.out; \ done mdbtools-0.7.1/src/000077500000000000000000000000001222645741400141405ustar00rootroot00000000000000mdbtools-0.7.1/src/Makefile.am000066400000000000000000000001541222645741400161740ustar00rootroot00000000000000SUBDIRS = libmdb extras $(OPTDIRS) util DIST_SUBDIRS = libmdb extras sql odbc gmdb2 util DEFDIR = $(prefix) mdbtools-0.7.1/src/extras/000077500000000000000000000000001222645741400154465ustar00rootroot00000000000000mdbtools-0.7.1/src/extras/Makefile.am000066400000000000000000000003071222645741400175020ustar00rootroot00000000000000bin_PROGRAMS = mdb-hexdump mdb_hexdump_SOURCES = mdb-dump.c mdbsupport.c EXTRA_DIST = mdbsupport.h AM_CFLAGS = -I$(top_srcdir)/include $(GLIB_CFLAGS) LDADD = ../libmdb/libmdb.la LIBS = $(GLIB_LIBS) mdbtools-0.7.1/src/extras/mdb-dump.c000066400000000000000000000042341222645741400173220ustar00rootroot00000000000000/* utility program to make a hex dump of a binary file (such as a mdb file) */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include int main(int argc, char **argv) { unsigned long i=0; unsigned int j; unsigned char data[17]; FILE *in; size_t length; int pg=0; char addr[10]; int jet4 = 0; int pg_size = 2048; if (argc < 2) { fprintf(stderr, "Usage: mdb-dump []\n\n"); exit(1); } if (argc>2) { if (!strncmp(argv[2],"0x",2)) { for (i=2;i '9' ? argv[2][i] - 'a' + 10 : argv[2][i] - '0'; } } else { pg = atol(argv[2]); } } printf("page num %d\n", pg); if ((in = fopen(argv[1],"r"))==NULL) { fprintf(stderr, "Couldn't open file %s\n", argv[1]); exit(1); } fseek(in,0x14,SEEK_SET); length = fread(data,1,1,in); if (!length) { fprintf(stderr, "fread failed at position 0x14\n"); exit(1); } if (data[0]) { jet4 = 1; pg_size = 4096; } fseek(in,(pg*pg_size),SEEK_SET); i = 0; while ((length = fread(data,1,16,in))) { sprintf(addr, "%06lx", i); //if (!strcmp(&addr[3],"000") || (!jet4 && !strcmp(&addr[3],"800")) && //pg) break; if (!strcmp(&addr[3],"000") || (!jet4 && !strcmp(&addr[3],"800"))) { fprintf(stdout,"-- Page 0x%04x (%d) --\n", pg, pg); pg++; } fprintf(stdout,"%s ", addr); i+=length; for(j=0; j #include void dump_int (int i) { fprintf (stdout, ">>%d<<\n", i); } void dump_long (long l) { fprintf (stdout, ">>%ld<<\n", l); } void dump_string (char *s) { if ((s == NULL) || (strlen (s) == 0)) fprintf (stdout, "(null)\n"); else fprintf (stdout, ">>%s<<\n", s); } mdbtools-0.7.1/src/extras/mdbsupport.h000066400000000000000000000001151222645741400200130ustar00rootroot00000000000000 void dump_int (int i); void dump_long (long l); void dump_string (char *s); mdbtools-0.7.1/src/gmdb2/000077500000000000000000000000001222645741400151335ustar00rootroot00000000000000mdbtools-0.7.1/src/gmdb2/Makefile.am000066400000000000000000000011551222645741400171710ustar00rootroot00000000000000SUBDIRS = help gladefiles pixmaps bin_PROGRAMS = gmdb2 include_HEADERS = gmdb.h gmdb2_SOURCES = main2.c file.c table.c info.c table_def.c table_data.c table_export.c debug.c sql.c schema.c prefs.c LIBS = -rdynamic $(GNOME_LIBS) @LIBS@ @LEXLIB@ AM_CFLAGS = -I$(top_srcdir)/include $(GNOME_CFLAGS) \ -DDATADIR="\"$(datadir)\"" \ -DGMDB_ICONDIR="\"$(datadir)/gmdb/glade/\"" \ -DGMDB_GLADEDIR="\"$(datadir)/gmdb/glade/\"" #LDADD = ../libmdb/libmdb.la LDADD = ../libmdb/libmdb.la ../sql/libmdbsql.la #if SQL #gmdb_LDADD = ../libmdb/libmdb.la ../sql/libmdbsql.la #endif mdbtools-0.7.1/src/gmdb2/debug.c000066400000000000000000001006531222645741400163720ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * 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. */ /* Objects attached to debug_window: * GList *nav_list: list of pages viewed, entries are guint32 *'s * guint *nav_elem: index to current page in nav_list * GladeXML *debugwin_xml: the associated glade hierarchy * gboolean *dissect: whether dissecting is turned on */ #include #include #include #include "gmdb.h" extern MdbHandle *mdb; GList *debug_list = NULL; #define LINESZ 77 /* prototypes */ static void gmdb_debug_init(MdbHandle *mdb, GladeXML *xml); static void gmdb_debug_text_on(GtkWidget *textbox, int start_byte, int end_byte); static void gmdb_debug_text_off(GtkWidget *textbox); static GtkTreeIter *gmdb_debug_add_item(GtkTreeStore *store, GtkTreeIter *iter, gchar *text, int start, int len); static void gmdb_debug_clear(GladeXML *xml); static void gmdb_debug_dissect(GtkTreeStore *store, char *fbuf, int offset, int len); static guint16 get_uint16(void *c); static guint32 get_uint32(void *c); static long gmdb_get_max_page(MdbHandle *mdb); static void gmdb_debug_display(GladeXML *xml, guint32 page); static void gmdb_debug_jump(GladeXML *xml, int msb); /* value to string stuff */ typedef struct GMdbValStr { gint value; gchar *string; } GMdbValStr; GMdbValStr table_types[] = { { 0x4e, "User" }, { 0x53, "System" }, { 0, NULL } }; GMdbValStr column_types[] = { { 0x01, "boolean" }, { 0x02, "byte" }, { 0x03, "int" }, { 0x04, "longint" }, { 0x05, "money" }, { 0x06, "float" }, { 0x07, "double" }, { 0x08, "short datetime" }, { 0x09, "binary" }, { 0x0a, "text" }, { 0x0b, "OLE" }, { 0x0c, "memo/hyperlink" }, { 0x0d, "Unknown" }, { 0x0f, "GUID" }, { 0, NULL } }; GMdbValStr object_types[] = { { 0x00, "Database Definition" }, { 0x01, "Data" }, { 0x02, "Table Definition" }, { 0x03, "Index" }, { 0x04, "Leaf Index" }, { 0, NULL } }; /* callbacks */ static void gmdb_debug_select_cb(GtkTreeSelection *select, GladeXML *xml) { int start_row, end_row; int start_col, end_col; GtkTreeIter iter; GtkTreeModel *model; gint32 start, end, len; GtkWidget *textview; gchar *fieldname; fprintf(stderr, "select_cb fired\n"); textview = glade_xml_get_widget (xml, "debug_textview"); gmdb_debug_text_off(textview); if (!select) return; if (!gtk_tree_selection_get_selected (select, &model, &iter)) return; gtk_tree_model_get (model, &iter, 0, &fieldname, 1, &start, 2, &len, -1); g_free (fieldname); if ((start == -1) || (len < 1)) return; end = start + len - 1; start_row = LINESZ * (start / 16); end_row = LINESZ * (end / 16); start_col = 8 + (start % 16) * 3; end_col = 8 + (end % 16) * 3; if (start_row == end_row) { gmdb_debug_text_on(textview, start_row + start_col, start_row + end_col + 2); gmdb_debug_text_on(textview, start_row + 59 + (start % 16), start_row + 59 + (end % 16) + 1); } else { int i; gmdb_debug_text_on(textview, start_row + start_col, /* 55 = 8 (addr) + 15 (bytes) * 3 (%02x " ") + 2 (last byte) */ start_row + 55); gmdb_debug_text_on(textview, start_row + 59 + (start % 16), start_row + 75); for (i=start_row + LINESZ; i < end_row; i+=LINESZ) { gmdb_debug_text_on(textview, i + 8, i + 55); gmdb_debug_text_on(textview, i + 59, i + 75); } gmdb_debug_text_on(textview, end_row + 8, end_row + end_col + 2); gmdb_debug_text_on(textview, end_row + 59, end_row + 59 + (end % 16) + 1); } } void gmdb_debug_forward_cb(GtkWidget *w, gpointer data) { guint *nav_elem; guint32 *page; GladeXML *xml; GList *nav_list; guint num_items; nav_list = g_object_get_data(G_OBJECT(w),"nav_list"); nav_elem = g_object_get_data(G_OBJECT(w),"nav_elem"); num_items = g_list_length(nav_list); if (!nav_elem || *nav_elem == num_items) return; (*nav_elem)++; g_object_set_data(G_OBJECT(w), "nav_elem", nav_elem); page = g_list_nth_data(nav_list,(*nav_elem) - 1); xml = g_object_get_data(G_OBJECT(w), "debugwin_xml"); gmdb_debug_display(xml, *page); } void gmdb_debug_back_cb(GtkWidget *w, gpointer data) { guint *nav_elem; guint32 *page; GladeXML *xml; GList *nav_list; nav_list = g_object_get_data(G_OBJECT(w),"nav_list"); nav_elem = g_object_get_data(G_OBJECT(w),"nav_elem"); if (!nav_elem || *nav_elem==1) return; /* at top of list already */ (*nav_elem)--; g_object_set_data(G_OBJECT(w), "nav_elem", nav_elem); page = g_list_nth_data(nav_list,(*nav_elem) - 1); xml = g_object_get_data(G_OBJECT(w), "debugwin_xml"); gmdb_debug_display(xml, *page); } static void gmdb_nav_add_page(GtkWidget *win, guint32 page_num) { GList *nav_list = NULL; GList *link = NULL; guint *nav_elem; guint num_items; int i; nav_list = g_object_get_data(G_OBJECT(win),"nav_list"); nav_elem = g_object_get_data(G_OBJECT(win),"nav_elem"); if (!nav_elem) { nav_elem = g_malloc0(sizeof(guint)); } /* * If we are positioned in the middle of the list and jumping from here * clear the end of the list first. */ num_items = g_list_length(nav_list); if (num_items > *nav_elem) { for (i=num_items - 1; i >= *nav_elem; i--) { link = g_list_nth(nav_list,i); nav_list = g_list_remove_link(nav_list, link); g_free(link->data); g_list_free_1(link); } } nav_list = g_list_append(nav_list, g_memdup(&page_num, 4)); *nav_elem = g_list_length(nav_list); g_object_set_data(G_OBJECT(win), "nav_list", nav_list); g_object_set_data(G_OBJECT(win), "nav_elem", nav_elem); } void gmdb_debug_jump_cb(GtkWidget *w, gpointer data) { gmdb_debug_jump(g_object_get_data(G_OBJECT(w), "debugwin_xml"), 0); } void gmdb_debug_jump_msb_cb(GtkWidget *w, gpointer data) { gmdb_debug_jump(g_object_get_data(G_OBJECT(w), "debugwin_xml"), 1); } static void gmdb_debug_jump(GladeXML *xml, int msb) { GtkTextView *textview; GtkTextBuffer *txtbuffer; GtkTextIter start, end; GtkWidget *entry; gchar *text; gchar page[12]; gchar digits[4][3]; gchar *hex_digit; int i, num_digits = 0; textview = (GtkTextView *) glade_xml_get_widget (xml, "debug_textview"); txtbuffer = gtk_text_view_get_buffer(textview); if (!gtk_text_buffer_get_selection_bounds(txtbuffer, &start, &end)) { /* FIX ME -- replace with text in status bar */ fprintf(stderr, "Nothing selected\n"); return; } text = g_strdup(gtk_text_buffer_get_text(txtbuffer, &start, &end, FALSE)); //fprintf(stderr, "selected text = %s\n",text); hex_digit = strtok(text, " "); strcpy(page, "0x"); do { if (strlen(hex_digit)>2) { fprintf(stderr, "Not a hex value\n"); return; } strcpy(digits[num_digits++],hex_digit); } while (num_digits < 4 && (hex_digit = strtok(NULL," "))); if (msb) { for (i=0;i=0;i--) { strcat(page, digits[i]); } } g_free(text); //fprintf(stderr, "going to page %s\n",page); entry = glade_xml_get_widget (xml, "debug_entry"); gtk_entry_set_text(GTK_ENTRY(entry),page); gmdb_debug_display_cb(entry, NULL); } /* * w: pointer to GtkEntry 'debug_entry' */ void gmdb_debug_display_cb(GtkWidget *w, gpointer data) { int page; GtkWidget *win; gchar *s; GladeXML *xml; fprintf(stderr, "display fired\n"); if (!mdb) return; win = gtk_widget_get_toplevel(w); xml = g_object_get_data(G_OBJECT(win), "debugwin_xml"); s = g_strdup(gtk_entry_get_text(GTK_ENTRY(w))); if (!strncmp(s,"0x",2)) { page = strtol(s+2, NULL, 16); } else { page = strtol(s, NULL, 10); } g_free(s); if (page>gmdb_get_max_page(mdb) || page<0) { GtkWidget* dlg = gtk_message_dialog_new (GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, _("Page entered is outside valid page range.")); gtk_dialog_run (GTK_DIALOG (dlg)); gtk_widget_destroy (dlg); } /* add to the navigation list */ gmdb_nav_add_page(win, page); /* gmdb_debug_display handles the mechanics of getting the page up */ gmdb_debug_display(xml, page); } static void gmdb_debug_display(GladeXML *xml, guint32 page) { char *fbuf; char *tbuf; int i, j; char line[80]; char field[10]; GtkTextBuffer *buffer; GtkTextIter iter; GtkTextView *textview; GtkWidget *entry, *window; char *pagestr; gboolean *dissect; GtkWidget *tree; GtkTreeView *store; textview = (GtkTextView *) glade_xml_get_widget (xml, "debug_textview"); gmdb_debug_clear(xml); pagestr = g_strdup_printf("%lu", (unsigned long)page); entry = glade_xml_get_widget (xml, "debug_entry"); gtk_entry_set_text(GTK_ENTRY(entry),pagestr); g_free(pagestr); mdb_read_pg(mdb, page); fbuf = g_malloc(mdb->fmt->pg_size); memcpy(fbuf, mdb->pg_buf, mdb->fmt->pg_size); tbuf = g_malloc0( (mdb->fmt->pg_size / 16) * sizeof(line)); i = 0; while (ifmt->pg_size) { sprintf(line,"%06x ", i); for(j=0; j<16; j++) { sprintf(field, "%02x ", ((unsigned char*)fbuf)[i+j]); strcat(line,field); } strcat(line, " |"); for(j=0; j<16; j++) { sprintf(field, "%c", (isprint(fbuf[i+j])) ? fbuf[i+j] : '.'); strcat(line,field); } strcat(line, "|\n"); i += 16; strcat(tbuf, line); } buffer = gtk_text_view_get_buffer(textview); gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0); gtk_text_buffer_insert(buffer,&iter,tbuf,strlen(tbuf)); tree = glade_xml_get_widget(xml, "debug_treeview"); store = (GtkTreeView *) gtk_tree_view_get_model(GTK_TREE_VIEW(tree)); window = glade_xml_get_widget(xml, "debug_window"); dissect = g_object_get_data(G_OBJECT(window),"dissect"); if (!dissect || *dissect) gmdb_debug_dissect(GTK_TREE_STORE(store), fbuf, 0, mdb->fmt->pg_size); g_free(fbuf); g_free(tbuf); } /* functions */ static long gmdb_get_max_page(MdbHandle *mdb) { struct stat st; assert( fstat(mdb->f->fd, &st)!=-1 ); return (st.st_size/mdb->fmt->pg_size)-1; } static gchar * gmdb_val_to_str(GMdbValStr *valstr, gint val) { gchar *strptr; int i = 0; do { strptr = valstr[i].string; if (val == valstr[i].value) { return strptr; } i++; } while (strptr); return "unknown"; } static guint16 get_uint16(void *c) { guint16 i; memcpy(&i, c, 2); return GINT16_FROM_LE(i); } static guint32 get_uint32(void *c) { guint32 l; memcpy(&l, c, 4); return GINT32_FROM_LE(l); } static void gmdb_debug_dissect_column(GtkTreeStore *store, GtkTreeIter *parent, char *fbuf, int offset) { gchar *str; unsigned char *foff = (unsigned char*)fbuf + offset; str = g_strdup_printf("Column Type: 0x%02x (%s)", foff[0], gmdb_val_to_str(column_types, foff[0])); gmdb_debug_add_item(store, parent, str, offset, 1); str = g_strdup_printf("Column #: %d", get_uint16(foff+1)); gmdb_debug_add_item(store, parent, str, offset+1, 2); str = g_strdup_printf("VarCol Offset: %d", get_uint16(foff+3)); gmdb_debug_add_item(store, parent, str, offset+3, 2); str = g_strdup_printf("Unknown"); gmdb_debug_add_item(store, parent, str, offset+5, 4); str = g_strdup_printf("Unknown"); gmdb_debug_add_item(store, parent, str, offset+9, 4); str = g_strdup_printf("Variable Column: %s", (foff[13] & 0x01) ? "No" : "Yes"); gmdb_debug_add_item(store, parent, str, offset+13, 1); str = g_strdup_printf("Fixed Col Offset: %d", get_uint16(foff+14)); gmdb_debug_add_item(store, parent, str, offset+14, 2); str = g_strdup_printf("Column Length: %d", get_uint16(foff+16)); gmdb_debug_add_item(store, parent, str, offset+16, 2); } static void gmdb_debug_dissect_index1(GtkTreeStore *store, GtkTreeIter *parent, char *fbuf, int offset) { gchar *str; gmdb_debug_add_item(store, parent, g_strdup("Unknown"), offset, 4); str = g_strdup_printf("Rows in Index: %lu", (unsigned long)get_uint32(fbuf+offset+4)); gmdb_debug_add_item(store, parent, str, offset+4, 4); } static void gmdb_debug_dissect_index2(GtkTreeStore *store, GtkTreeIter *parent, char *fbuf, int offset) { gchar *str; unsigned char flags; str = g_strdup("Column mask"); gmdb_debug_add_item(store, parent, str, offset, 30); str = g_strdup("Unknown"); gmdb_debug_add_item(store, parent, str, offset+30, 4); str = g_strdup("Root index page"); gmdb_debug_add_item(store, parent, str, offset+34, 4); flags = fbuf[offset+38]; str = g_strconcat("Index Flags:", (flags & MDB_IDX_UNIQUE) ? " Unique" : "", (flags & MDB_IDX_IGNORENULLS) ? " IgnoreNulls" : "", (flags & MDB_IDX_REQUIRED) ? " Required" : "", NULL); if (strcmp(str, "Index Flags:") == 0) { gchar *str2 = g_strconcat(str, " None", NULL); g_free(str); str = str2; } gmdb_debug_add_item(store, parent, str, offset+38, 1); } static void gmdb_debug_add_page_ptr(GtkTreeStore *store, GtkTreeIter *parent, char *fbuf, const char *label, int offset) { gchar *str; GtkTreeIter *node; guint32 pg_row = get_uint32(fbuf+offset); str = g_strdup(label); node = gmdb_debug_add_item(store, parent, str, offset, 4); str = g_strdup_printf("Row Number: %u", pg_row & 0xff); gmdb_debug_add_item(store, node, str, offset, 1); str = g_strdup_printf("Page Number: %u", pg_row >> 8); gmdb_debug_add_item(store, node, str, offset+1, 3); } static void gmdb_debug_dissect_row(GtkTreeStore *store, GtkTreeIter *parent, char *fbuf, int offset, int len) { gchar *str; int bitmask_sz; int num_cols, var_cols, var_cols_loc, fixed_end, eod_ptr; int i; num_cols = fbuf[offset]; str = g_strdup_printf("Num columns: %u", num_cols); gmdb_debug_add_item(store, parent, str, offset, 1); bitmask_sz = (num_cols+7) / 8; var_cols_loc = offset + len - bitmask_sz - 1; var_cols = fbuf[var_cols_loc]; fixed_end = offset + fbuf[var_cols_loc - 1] - 1; /* work even if 0 b/c of EOD */ str = g_strdup("Fixed columns"); gmdb_debug_add_item(store, parent, str, offset + 1, fixed_end - offset); for (i=0;ifmt->pg_size - row_start; else row_len = (get_uint16(fbuf+offset+14+(i-1)*2) & 0x0FFF) - row_start; str = g_strdup_printf("Row %d", i+1); /*container = */gmdb_debug_add_item(store, NULL, str, row_start, row_len); /* usage pages have parent id of 0 (database) and do not * follow normal row format */ /* if (tdef) gmdb_debug_dissect_row(store, container, fbuf, row_start, row_len); */ } } static void gmdb_debug_dissect_data_pg3(GtkTreeStore *store, char *fbuf, int offset, int len) { gchar *str; int num_rows, i, row_start, row_len; guint32 tdef; GtkTreeIter *container; str = g_strdup_printf("Page free space: %u", get_uint16(fbuf+offset+2)); gmdb_debug_add_item(store, NULL, str, offset+2, 2); tdef = get_uint32(fbuf+offset+4); str = g_strdup_printf("Parent's TDEF page: 0x%06x (%lu)", tdef, (unsigned long)tdef); gmdb_debug_add_item(store, NULL, str, offset+4, 4); num_rows = get_uint16(fbuf+offset+8); str = g_strdup_printf("Num rows: %u", num_rows); gmdb_debug_add_item(store, NULL, str, offset+8, 2); for (i=0;ifmt->pg_size - row_start; else row_len = (get_uint16(fbuf+offset+10+(i-1)*2) & 0x0FFF) - row_start; str = g_strdup_printf("Row %d", i+1); container = gmdb_debug_add_item(store, NULL, str, row_start, row_len); /* usage pages have parent id of 0 (database) and do not * follow normal row format */ if (tdef) gmdb_debug_dissect_row(store, container, fbuf, row_start, row_len); } } static void gmdb_debug_dissect_data_pg(GtkTreeStore *store, char *fbuf, int offset, int len) { if (IS_JET3(mdb)) gmdb_debug_dissect_data_pg3(store, fbuf, offset, len); else gmdb_debug_dissect_data_pg4(store, fbuf, offset, len); } static void gmdb_debug_dissect_tabledef_pg4(GtkTreeStore *store, char *fbuf, int offset, int len) { gchar *str; guint32 i, num_idx, num_cols, idx_entries; int newbase, infobase; GtkTreeIter *container; char *foff = fbuf + offset; str = g_strdup_printf("Next TDEF Page: 0x%06x (%lu)", get_uint32(foff+4), (unsigned long)get_uint32(foff+4)); gmdb_debug_add_item(store, NULL, str, offset+4, 4); str = g_strdup_printf("Length of Data: %lu", (unsigned long)get_uint32(foff+8)); gmdb_debug_add_item(store, NULL, str, offset+8, 4); str = g_strdup_printf("Records: %lu", (unsigned long)get_uint32(foff+16)); gmdb_debug_add_item(store, NULL, str, offset+16, 4); str = g_strdup_printf("Autonumber Value: %lu", (unsigned long)get_uint32(foff+20)); gmdb_debug_add_item(store, NULL, str, offset+20, 4); str = g_strdup_printf("Table Type: 0x%02x (%s)", foff[40], gmdb_val_to_str(table_types, foff[40])); gmdb_debug_add_item(store, NULL, str, offset+40, 1); str = g_strdup_printf("Max Columns: %u", get_uint16(foff+41)); gmdb_debug_add_item(store, NULL, str, offset+41, 2); str = g_strdup_printf("Var Columns: %u", get_uint16(foff+43)); gmdb_debug_add_item(store, NULL, str, offset+43, 2); num_cols = get_uint16(foff+45); str = g_strdup_printf("Columns: %u", num_cols); gmdb_debug_add_item(store, NULL, str, offset+45, 2); idx_entries = get_uint32(foff+47); str = g_strdup_printf("Index Entries: %lu", (unsigned long)idx_entries); gmdb_debug_add_item(store, NULL, str, offset+47, 4); num_idx = get_uint32(foff+51); str = g_strdup_printf("Real Indices: %lu", (unsigned long)num_idx); gmdb_debug_add_item(store, NULL, str, offset+51, 4); gmdb_debug_add_page_ptr(store, NULL, fbuf, "Used Pages Pointer", offset+55); gmdb_debug_add_page_ptr(store, NULL, fbuf, "Pages Freespace Pointer", offset+59); newbase = offset+63; if (num_idx > 0) { str = g_strdup("Index Entries"); container = gmdb_debug_add_item(store, NULL, str, -1, 0); } for (i=0;i #include #include #include #include #include "mdbtools.h" #include "gmdb.h" MdbHandle *mdb; extern int main_show_debug; extern GladeXML *mainwin_xml; #define MAX_ACTIONITEMS 9 #define MAX_ICONVIEWS 6 typedef struct { GtkWidget* actionitems[MAX_ACTIONITEMS]; GtkWidget* iconviews[MAX_ICONVIEWS]; } GmdbWidgets; GmdbWidgets* gmdbwidgets = NULL; static void gmdb_file_open_recent(gchar *menuname) { gchar *text, cfgname[100]; sprintf(cfgname,"/gmdb/RecentFiles/%s.filepath", menuname); text = gnome_config_get_string(cfgname); gmdb_file_open(text); g_free(text); gmdb_load_recent_files(); } void gmdb_file_open_recent_1() { gmdb_file_open_recent("menu_recent1"); } void gmdb_file_open_recent_2() { gmdb_file_open_recent("menu_recent2"); } void gmdb_file_open_recent_3() { gmdb_file_open_recent("menu_recent3"); } void gmdb_file_open_recent_4() { gmdb_file_open_recent("menu_recent4"); } static void gmdb_file_shuffle_recent(gchar *file_path) { gchar *text, cfgname[100]; int i, index=0; for (i=1; i<=4; i++) { sprintf(cfgname,"/gmdb/RecentFiles/menu_recent%d.filepath", i); text = gnome_config_get_string(cfgname); if (text && !strcmp(text,file_path)) { index = i; break; } g_free(text); } /* printf("found file %slocation at menu %d\n",file_path, index); */ /* it is the most recently used file, we're done */ if (index==1) return; /* if this file is not on the recent list bump item 4 */ if (!index) index=4; for (i=1; i=0 && file_path[i]!='/';i--); if (file_path[i]=='/') { strncpy(basename,&file_path[i+1],32); } else { strncpy(basename,file_path,32); } basename[32]='\0'; gnome_config_set_string("/gmdb/RecentFiles/menu_recent1.basename", basename); gnome_config_set_string("/gmdb/RecentFiles/menu_recent1.filepath", file_path); gnome_config_sync(); } static void gmdb_reset_widgets (GmdbWidgets* gw) { int i; GtkWidget *w; gmdb_table_set_sensitive (FALSE); for (i = 0; i < MAX_ACTIONITEMS; ++i) { w = gw->actionitems[i]; gtk_widget_set_sensitive (w, FALSE); } for (i = 0; i < MAX_ICONVIEWS; ++i) { w = gw->iconviews[i]; gtk_list_store_clear (GTK_LIST_STORE (gtk_icon_view_get_model (GTK_ICON_VIEW (w)))); } w = glade_xml_get_widget (mainwin_xml, "gmdb"); gtk_window_set_title (GTK_WINDOW (w), "MDB File Viewer"); } static void gmdb_icon_list_fill (MdbHandle* mdb, GtkTreeModel* store, GdkPixbuf* pixbuf, int objtype) { int i; MdbCatalogEntry* entry; GtkTreeIter iter; for (i=0; i < mdb->num_catalog; i++) { entry = g_ptr_array_index (mdb->catalog, i); if (entry->object_type == objtype) { /* skip the MSys tables - FIXME: can other objects be hidden too? */ if (objtype != MDB_TABLE || mdb_is_user_table (entry)) { gtk_list_store_prepend (GTK_LIST_STORE (store), &iter); gtk_list_store_set (GTK_LIST_STORE (store), &iter, 0, pixbuf, 1, entry->object_name, -1); } } } } static void gmdb_file_init (void) { GtkWidget* w; GtkListStore* store; int i; gchar* ainames[] = { "sql_menu", "debug_menu", "schema_menu", "info_menu", "close_menu", "sql_button", "schema_button", "info_button", "close_button" }; gchar* swnames[] = { "sw_form", "sw_macro", "sw_module", "sw_query", "sw_report", "sw_table" }; if (gmdbwidgets) { return; } gmdbwidgets = g_new0 (GmdbWidgets, 1); for (i = 0; i < MAX_ACTIONITEMS; ++i) { gmdbwidgets->actionitems[i] = glade_xml_get_widget (mainwin_xml, ainames[i]); } for (i = 0; i < MAX_ICONVIEWS; ++i) { store = gtk_list_store_new (2, GDK_TYPE_PIXBUF, G_TYPE_STRING); gmdbwidgets->iconviews[i] = gtk_icon_view_new(); gtk_icon_view_set_model (GTK_ICON_VIEW (gmdbwidgets->iconviews[i]), GTK_TREE_MODEL (store)); gtk_icon_view_set_pixbuf_column (GTK_ICON_VIEW (gmdbwidgets->iconviews[i]), 0); gtk_icon_view_set_text_column (GTK_ICON_VIEW (gmdbwidgets->iconviews[i]), 1); w = glade_xml_get_widget (mainwin_xml, swnames[i]); gtk_container_add (GTK_CONTAINER (w), gmdbwidgets->iconviews[i]); gtk_widget_show_all (w); } g_signal_connect_after (gmdbwidgets->iconviews[5], "selection-changed", G_CALLBACK (gmdb_table_select_cb), NULL); gmdb_table_init_popup (gmdbwidgets->iconviews[5]); } void gmdb_file_open(gchar *file_path) { GtkWidget *win; GdkPixbuf *pixbuf; GtkTreeModel *store; gchar *file_name; gchar title[100]; int i; gchar* pbnames[] = { GMDB_ICONDIR "form_big.xpm", GMDB_ICONDIR "macro_big.xpm", GMDB_ICONDIR "module_big.xpm", GMDB_ICONDIR "query_big.xpm", GMDB_ICONDIR "report_big.xpm", GMDB_ICONDIR "table_big.xpm" }; int objtype[] = { MDB_FORM, MDB_MACRO, MDB_MODULE, MDB_QUERY, MDB_REPORT, MDB_TABLE }; if (!gmdbwidgets) { gmdb_file_init(); } gmdb_reset_widgets (gmdbwidgets); mdb = mdb_open(file_path, MDB_NOFLAGS); if (!mdb) { GtkWidget* dlg = gtk_message_dialog_new (NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, _("Unable to open file.")); gtk_dialog_run (GTK_DIALOG (dlg)); gtk_widget_destroy (dlg); return; } mdb_set_default_backend(mdb, "access"); gmdb_file_shuffle_recent(file_path); gmdb_file_add_recent(file_path); #ifdef SQL sql->mdb = mdb; #endif mdb_read_catalog(mdb, MDB_ANY); for (i = 0; i < MAX_ICONVIEWS; ++i) { store = gtk_icon_view_get_model (GTK_ICON_VIEW (gmdbwidgets->iconviews[i])); pixbuf = gdk_pixbuf_new_from_file (pbnames[i], NULL); gmdb_icon_list_fill (mdb, store, pixbuf, objtype[i]); g_object_unref (pixbuf); } //if (main_show_debug) gmdb_debug_init(mdb); for (i=strlen(file_path);i>0 && file_path[i-1]!='/';i--); file_name=&file_path[i]; win = (GtkWidget *) glade_xml_get_widget (mainwin_xml, "gmdb"); g_snprintf(title, 100, "%s - MDB File Viewer",file_name); gtk_window_set_title(GTK_WINDOW(win), title); for (i = 0; i < MAX_ACTIONITEMS; ++i) { win = gmdbwidgets->actionitems[i]; gtk_widget_set_sensitive (win, TRUE); } } void gmdb_file_select_cb(GtkWidget *button, gpointer data) { GtkWindow *parent_window = (GtkWindow *) glade_xml_get_widget (mainwin_xml, "gmdb"); GtkWidget *dialog = gtk_file_chooser_dialog_new ("Please select a database.", parent_window, GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) { char *filename; filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); gmdb_file_open(filename); gmdb_load_recent_files(); } gtk_widget_destroy (dialog); } void gmdb_file_close_cb(GtkWidget *button, gpointer data) { gmdb_reset_widgets (gmdbwidgets); gmdb_debug_close_all(); #if SQL gmdb_sql_close_all(); #endif } mdbtools-0.7.1/src/gmdb2/gladefiles/000077500000000000000000000000001222645741400172325ustar00rootroot00000000000000mdbtools-0.7.1/src/gmdb2/gladefiles/Makefile.am000066400000000000000000000004021222645741400212620ustar00rootroot00000000000000gladedir = $(datadir)/gmdb/glade glade_DATA = \ gmdb.glade \ gmdb-sql.glade \ gmdb-debug.glade \ gmdb-export.glade \ gmdb-schema.glade \ gmdb-prefs.glade \ gmdb-props.glade \ gmdb-tabledef.glade \ ../../../COPYING EXTRA_DIST = $(glade_DATA) mdbtools-0.7.1/src/gmdb2/gladefiles/gmdb-debug.glade000066400000000000000000000420421222645741400222270ustar00rootroot00000000000000 True MDB File Viewer True True True File gtk-new True True True True gtk-close True True True True View True _Dissector True True True _Back True gtk-new True True True True True _Selected Page True True Selected Page (_MSB) True True Help gtk-about True True True False 0 True True 1 icons True Open a new window True gtk-new False True True False True Back True gtk-go-back False True True Forward True gtk-go-forward False True True Jump to True gtk-jump-to False True True False True Close window True gtk-close False True 1 True True 0 none True 12 True Page Number False False 0 True False False 1 True True 2 _Display True True False True False False 3 False False 0 True True True True automatic automatic True True False False True True True automatic automatic True True True True 1 2 True 2 True 0 False 3 mdbtools-0.7.1/src/gmdb2/gladefiles/gmdb-export.glade000066400000000000000000000355431222645741400224720ustar00rootroot00000000000000 True Export Table Data normal True True 30 7 2 30 8 True 0 <b>File Name:</b> True GTK_FILL True 0 <b>Line Terminator:</b> True 1 2 GTK_FILL True 0 <b>Column Separator:</b> True 2 3 GTK_FILL True 0 <b>Options:</b> True 6 7 GTK_FILL Include Headers True True False True True True 1 2 6 7 GTK_FILL True 1 2 1 2 True 1 2 2 3 True 0 <b>Binaries:</b> True 5 6 GTK_FILL True 1 2 5 6 True 0 <b>Quote Character:</b> True 3 4 GTK_FILL True 1 2 3 4 True 0 <b>Escape Character:</b> True 4 5 GTK_FILL True 1 2 4 5 True True table.csv 1 2 2 end gtk-help -11 True True True False True False False 0 gtk-cancel -6 True True True False True False False 1 -5 True True True False True 0 0 True 2 True gtk-convert False False 0 True _Export True False False 1 False False 2 gtk-save True True False True False False 3 False end 0 mdbtools-0.7.1/src/gmdb2/gladefiles/gmdb-prefs.glade000066400000000000000000000111441222645741400222570ustar00rootroot00000000000000 True Preferences normal True True 10 2 True 0 <b>Maximum Rows to Display:</b> True True True 1 2 GTK_FILL False 2 True end gtk-help -11 True True True False True False False 0 gtk-cancel -6 True True True False True False False 1 gtk-ok -5 True True True False True False False 2 False end 0 mdbtools-0.7.1/src/gmdb2/gladefiles/gmdb-props.glade000066400000000000000000000332751222645741400223140ustar00rootroot00000000000000 True dialog1 normal True True 10 9 2 30 8 True 0 1 2 4 5 GTK_FILL True 0 <b>Number of Objects:</b> True right 5 6 True 0 <b>Number of Pages:</b> True right 4 5 True 0 <b>File Size:</b> True right 3 4 True 0 <b>JET Version:</b> True right 1 2 True 0 <b>File Name:</b> True right okbutton1 True 0 1 2 GTK_FILL True 0 1 2 3 4 GTK_FILL True 0 1 2 5 6 GTK_FILL True 0 1 2 1 2 GTK_FILL True 0 <b>Title:</b> True 6 7 GTK_FILL True 0 <b>Author:</b> True 7 8 GTK_FILL True 0 1 2 6 7 GTK_FILL True 0 1 2 7 8 GTK_FILL True 0 1 2 8 9 GTK_FILL True 0 <b>Company:</b> True 8 9 GTK_FILL True 0 <b>Encrypted:</b> True 2 3 GTK_FILL True 0 1 2 2 3 GTK_FILL False False 2 True end gtk-ok -5 True True True False True False False 0 False end 0 mdbtools-0.7.1/src/gmdb2/gladefiles/gmdb-schema.glade000066400000000000000000000424141222645741400224040ustar00rootroot00000000000000 True Export Schema normal True True 33 5 2 30 8 True 0 <b>Table:</b> True right 1 2 GTK_FILL True 0 <b>Schema Dialect:</b> True right 2 3 GTK_FILL Include Relationships True True False True True True 1 2 9 10 GTK_FILL True 0 <b>Options:</b> True right 3 4 GTK_FILL Include Drop Table commands True True False True True True 1 2 3 4 GTK_FILL Include Not Null constraints True True False True True True 1 2 4 5 GTK_FILL Include indexes True True False True True True 1 2 8 9 GTK_FILL Include description on tables and columns True True False True True True 1 2 7 8 GTK_FILL Include Not Empty constraints True True False True True True 1 2 6 7 GTK_FILL Include Default values True True False True True True 1 2 5 6 GTK_FILL True 0 <b>File Name:</b> True GTK_FILL True 1 2 1 2 True 0 Access Oracle Sybase MS SQL Server PostgreSQL MySQL SQLite 1 2 2 3 True True export.sql 1 2 False 2 True end gtk-help -11 True True True False True False False 0 gtk-cancel -6 True True True False True False False 1 -5 True True True False True 0 0 True 2 True gtk-convert False False 0 True _Export True False False 1 False False 2 False end 0 mdbtools-0.7.1/src/gmdb2/gladefiles/gmdb-sql.glade000066400000000000000000000457051222645741400217510ustar00rootroot00000000000000 True MDB File Viewer True True True _Query True gtk-new True True True gtk-open True True True gtk-save True True True gtk-save-as True True True Save _Results... True True False True stock_export-16.png True gtk-execute True True True True gtk-close True True True True Edit gtk-cut True True True gtk-copy True True True gtk-paste True True True True Help gtk-about True True True False 0 True True 1 icons True Start new query gtk-new False True True Load query from file gtk-open False True True Save query to file Save Results True gtk-save False True True Execute query gtk-execute False True True Save results to a file Save Results True stock_export.png False True True Close this window gtk-close False True 1 True True True True True 5 0 in True True automatic automatic True True False False True True True 4 0 in True True never automatic 50 True True 0 True 5 True Recent Queries: False False 0 True 1 False False 1 True True False True True 3 0 in True True automatic automatic True True True True 2 True 2 True 0 False 3 mdbtools-0.7.1/src/gmdb2/gladefiles/gmdb-tabledef.glade000066400000000000000000000275511222645741400227170ustar00rootroot00000000000000 True vertical True True automatic automatic True True both 0 True 10 2 True Size True True False 1 2 True True False 1 2 8 9 True Required 8 9 True Format 1 2 True True False 1 2 1 2 True Input mask 3 4 True True False 1 2 3 4 True Caption 4 5 True Default value 5 6 True Validation rule 6 7 True Validation error message 7 8 True Allow zero length 9 10 True True False 1 2 4 5 True True False 1 2 5 6 True True False 1 2 6 7 True True False 1 2 7 8 True True False 1 2 9 10 True Decimal places 2 3 True True False 1 2 2 3 False 1 mdbtools-0.7.1/src/gmdb2/gladefiles/gmdb.glade000066400000000000000000001217161222645741400211510ustar00rootroot00000000000000 True MDB File Viewer True True True True True 1 icons True Open database file gtk-open False True True False View database file properties gtk-properties False True True False Close database file gtk-close False True True False Perform SQL query gtk-execute False True True False Export schema definition gtk-convert False True 1 BONOBO_DOCK_ITEM_BEH_EXCLUSIVE True True True _File True gtk-open True True True True gtk-properties True False True True True gtk-close True False True True True True item True True item3 True True item4 True True item5 True True gtk-quit True True True True _Edit True gtk-preferences True True True True _Tools True S_QL Window True False True False True gtk-execute _Debug Window True False True False True gtk-find E_xport Schema True False True False True gtk-convert True _Help True gtk-about True True True True gtk-help True True True BONOBO_DOCK_ITEM_BEH_EXCLUSIVE | BONOBO_DOCK_ITEM_BEH_NEVER_VERTICAL | BONOBO_DOCK_ITEM_BEH_LOCKED True True True True True True 10 0 in True True automatic automatic 0 120 True 18 vertical 10 Definition True True False True False False 0 Data True True False True False False 1 Export True True False True False False 2 False False 1 True 2 True table.xpm 0 True Tables False False 1 False tab True True 10 0 in True True automatic automatic 0 True False False 1 1 True 2 True query.xpm 0 True Queries False False 1 1 False tab True True 10 0 in True True automatic automatic 0 True False False 1 2 True 2 True forms.xpm 0 True Forms False False 1 2 False tab True True 10 0 in True True automatic automatic 0 True False False 1 3 True 2 True reports.xpm 0 True Reports False False 1 3 False tab True True 10 0 in True True automatic automatic 0 True False False 1 4 True 2 True macros.xpm 0 True Macros False False 1 4 False tab True True 10 0 in True True automatic automatic 0 True False False 1 5 True 2 True code.xpm 0 True Modules False False 1 5 False tab 0 True True True 4 True True 1 True True mdbtools-0.7.1/src/gmdb2/gmdb.h000066400000000000000000000066111222645741400162210ustar00rootroot00000000000000#ifndef _gmdb_h_ #define _gmdb_h_ #include #include #include #include #include #include #include "mdbtools.h" #include "mdbsql.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* info.c */ GtkWidget *gmdb_info_new(void); /* main2.c */ void gmdb_info_cb(GtkWidget *w, gpointer data); void gmdb_prefs_cb(GtkWidget *w, gpointer data); void gmdb_help_cb(GtkWidget *w, gpointer data); void gmdb_about_cb(GtkWidget *w, gpointer data); void gmdb_load_recent_files(void); GtkWidget *gmdb_table_data_new(MdbCatalogEntry *entry); GtkWidget *gmdb_table_export_new(MdbCatalogEntry *entry); void gmdb_table_export(MdbCatalogEntry *entry) ; void gmdb_table_export_populate_dialog(GladeXML *xml); /* table_def.c */ void gmdb_table_def_new(MdbCatalogEntry *entry); /* file.c */ void gmdb_file_select_cb(GtkWidget *w, gpointer data); void gmdb_file_close_cb(GtkWidget *w, gpointer data); void gmdb_file_open_recent_1(void); void gmdb_file_open_recent_2(void); void gmdb_file_open_recent_3(void); void gmdb_file_open_recent_4(void); void gmdb_file_open(gchar *file_path); void gmdb_sql_new_window_cb(GtkWidget *w, gpointer data); void gmdb_table_add_tab(GtkWidget *notebook); void gmdb_debug_tab_new(GtkWidget *notebook); /* debug.c */ void gmdb_debug_jump_cb(GtkWidget *w, gpointer data); void gmdb_debug_jump_msb_cb(GtkWidget *w, gpointer data); void gmdb_debug_display_cb(GtkWidget *w, gpointer data); void gmdb_debug_close_cb(GtkWidget *w, gpointer data); void gmdb_debug_forward_cb(GtkWidget *w, gpointer data); void gmdb_debug_back_cb(GtkWidget *w, gpointer data); void gmdb_debug_new_cb(GtkWidget *w, gpointer data); void gmdb_debug_set_dissect_cb(GtkWidget *w, gpointer data); void gmdb_debug_close_all(void); /* sql.c */ void gmdb_sql_new_cb(GtkWidget *w, gpointer data); void gmdb_sql_close_all(void); unsigned long gmdb_prefs_get_maxrows(void); extern GtkWidget *gmdb_prefs_new(void); /* schema.c */ void gmdb_schema_new_cb(GtkWidget *w, gpointer data); void gmdb_schema_export_cb(GtkWidget *w, gpointer data); void gmdb_schema_help_cb(GtkWidget *w, gpointer data); /* table.c */ void gmdb_table_debug_cb(GtkList *list, GtkWidget *w, gpointer data); void gmdb_table_export_cb(GtkList *list, GtkWidget *w, gpointer data); void gmdb_table_def_cb(GtkList *list, GtkWidget *w, gpointer data); void gmdb_table_unselect_cb (GtkIconView*, gpointer); void gmdb_table_select_cb (GtkIconView*, gpointer); void gmdb_table_data_cb(GtkList *list, GtkWidget *w, gpointer data); void gmdb_table_init_popup (GtkWidget*); void gmdb_table_set_sensitive(gboolean b); /* table_export.c */ void gmdb_export_get_delimiter(GladeXML *xml, gchar *delimiter, int max_buf); void gmdb_export_get_lineterm(GladeXML *xml, gchar *lineterm, int max_buf); void gmdb_export_get_quotechar(GladeXML *xml, gchar *quotechar, int max_buf); void gmdb_export_get_escapechar(GladeXML *xml, gchar *escapechar, int max_buf); int gmdb_export_get_binmode(GladeXML *xml); int gmdb_export_get_headers(GladeXML *xml); gchar *gmdb_export_get_filepath(GladeXML *xml); void gmdb_export_help_cb(GtkWidget *w, gpointer data); void gmdb_print_col(FILE *outfile, gchar *col_val, int quote_text, int col_type, int bin_len, char *quote_char, char *escape_char, int bin_mode); void gmdb_table_export_button_cb(GtkWidget *w, gpointer data); extern MdbSQL *sql; #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #endif mdbtools-0.7.1/src/gmdb2/help/000077500000000000000000000000001222645741400160635ustar00rootroot00000000000000mdbtools-0.7.1/src/gmdb2/help/C/000077500000000000000000000000001222645741400162455ustar00rootroot00000000000000mdbtools-0.7.1/src/gmdb2/help/C/Makefile.am000066400000000000000000000002201222645741400202730ustar00rootroot00000000000000include $(top_srcdir)/xmldocs.make dist-hook: app-dist-hook figdir = figures docname = gmdb lang = C omffile = gmdb-C.omf entities = legal.xml mdbtools-0.7.1/src/gmdb2/help/C/figures/000077500000000000000000000000001222645741400177115ustar00rootroot00000000000000mdbtools-0.7.1/src/gmdb2/help/C/figures/gmdb2_sql_window.png000066400000000000000000001323011222645741400236600ustar00rootroot00000000000000‰PNG  IHDRíĹÉËPöbKGD˙˙˙ ˝§“ pHYs  ŇÝ~ütIMEÓ#Ęf+Ç IDATxśěÝluş?ú'_ąW3«ôjĄ_y˘e˘Őˇ Ú´GŤ «Ć٠š«Ű¤E"N{D@4aWlR¤Ý›dŰ„ŐaЦ«Sâ Ń&=ÚnĚW”:R§:@Śh×®–¨cmŁĚHŤŃMÄ|tk©÷ŹqĆcgü3Nóëy íľ3žßˇőĂgž™)ę|ł Nţţ$ „B­HßţĎ·Ć‹¦§§µTZZ ÷îÝËiu»›Ný©§P;‡ąčrďB­QÇßh}=÷âŢł^ĎĎý\Ľ¨¨ ŐŚEűżŇŇR­‚ …CÚÚBÇŠÍ”…Jšá°’ănŁő‹”#˛Ü;€Đş5śXřź}%p?×Ę•˘˘"í‚’ć‹ĐőPŰI’é,†ďď”™‚hěolĘB‘ś2E˛”ą"s&™)¦”T™íĐ˛Ę ĄĚ-e.ˇ%–­%””2ö+Č9[)eH2«Ě¨‹ĎüfV”ÖNV ˛ž2VśZCYRµ?ž1/EÖ-¦ ąĎ‹‹·E°Ŕ·ß>ćxlzzÚ˛pľ,·­ąŞŃ„s±®Y ˙EiČ´…Rç˙Ťˇ-”J=˦™JťçrÉĹć™-¦d˘h_ęÉyÎ<‹zf˛ĚDűâOΊIćJ(E!ęâł•QfâYĘ%ó©ňfF’ ťËiJ6Ď’¬’˛K®X꼕¦ÖzŢΑ%ĚŽíL3ćű'n&^QÉ˝XĆĹc?ĹcrĽś”°íő|ů i”%ˇXÉ{ŢtŇhéMćˇ(u.—\L©$6Ň`Ěl1%ĎeĘLR†Ś™(&™+ˇ”äL˛ÍVJ™ÓB$sŢĚ(Ů3$öĄž*—1’”C®(c=oe„©ĺÎŰ!˛Ěٱť ç”wpáIyisDÖţ,IŢÉ…'ďSvbĆĽd9övQ…$.Ţz¬š˙Ô{Ö›~qÚB7˝Đ čµ)Ţ3^} ż™żüŮĺŇŇŇ„ŞFßőŘ*Î $íşÖŚ3<4›H›€w] ÜV»NŤkS<l®*Nť…Ö? ôş`Clfu“ňȧ‚()Đ÷¶‹¦Ö&ŢV˝Ăá›É]8ś•Ş{ĘfŰĘŇAť…ŕMqä˘ +É;SXm/Ů+llŇÄĐrďűA˝ˇ, ›çřČ EQ Fa||¤˛˛NVâÓSćůŃŞ81+†CM3“gâYžQČÂ\Ď\ę,J„Ě(ćŮʤĚSĆé ™/2˛ĘSń,čą,·l+c„Č|ŢšUóä|Ţž:Gí ]b¶šfG®y‡54Yř,L*r.9lšw¦Î7ĹĹgçRç]©óŤű—zŢsásĚR Ą,řT—fq­€¦š´:Dźâ9ęŃĘ ăâńu'1Đt´IŻ›ô"†ş±ˇqphP_”DU“ťŕ·ĐŇLaĘŔľ“Ńć ^÷Űl•Ú -Ż°Ĺ”«Ęîz˘Â¶ť=ů–_śQ@Uˇ˝c,@[ŔľĂćip6¶5¶Ś0ĹŚľrÎĘvĽâ¤i8_ěŰ9OËľťik\QĚ÷§ †.†ÉÇ‚:Gúßi€–߀2G„Ű2ĎŰ,z=”…VjȱF"Š˘•ąxS‘žŤÓ)ŠV<_¬$ć9yľď$!‹¦™IĚŠy–˘ý™’Ä<Ë\ -šg6ž­¬¨BĚňŚ’>ó›˛ eĘe©ó”I¶ióĚ©`ŰšĂĆ<Ąg.ž·§Ě”˘Ě©`ßÎ łĽ#M–Ls(×<™KŢ™{ŽHÚź)cvf™'sÉ»rÎK›ů‰›fyOa˛+Ź|3ćç$91‰JÎEL¦Ĺ›Ž6e¬,é·í9ęцqô"fᶉŮu%ńŽĚmb+wZÇo[ÇÓŞš<˙řxŰbÜWŁP[UQ÷”µűý0@T˙:Ěm±€ ‰žQSó4˛Ń4ôĽ;:tnŚ)á'&č χ»Šyďců|=mú–QüŹZ=óelËł6~3+Ď©C˙WôśtŔÄ É±Ă*Î(N;×őŢDđ;ŽŞpě°¶ţŢŻo7<© ŻPp`Śćx;D)văŞâëöńě&ZľŁŽ|!řÇ$­q×đużŕYv~ú•Ř7DŇ ¤(Z!*,ĚĹ´2§ —x–L3C+s±u2 ­()ň\¬ŢbJ´¬€µ„Vó,ĆsĽ@±ZóL†ĚoN™ÉgV(đe©łϢD´Sj3ć­ Y0ć)łl(J’ ”)%öEnĚ;r8UŽĺťąĺĘćÉ\ň®”y"˘(39äPD‘2ćÉ<łkOŞĚ‡&ĄÂç›fůńśóDÎYÁŚąŕYűTŁ*,˘1Y|Áztř`@OIZÜ{Ö»pń[°ŔŔ™cä9»±[/b?ÔBě&šו p-\żßézÂćż2VyŔřN´me˘ óSОPccRmU…}'/‹#°Đ•»mś•§(pUŮTşßIŘ6|—‚ Ăł­üZńç.[÷;~PŁ „ÇxľRĎöGŞ:_q˘¶´y=‡ě-G*ׂdޞ–Đ4 e×ÂÁëa§Ýă´Qă—$†µşçĎüŐ/ü0Îo±'ü ĄXŔýK[ÓˇŠŔ×B˙ď}MĎV5Ş łŠ˙ 9>ýŻ ÓN!E‘9}Ä%1ëŁ&Ĺ”’U­ż„a2™ż“%]VTí’SB‘™X¶–PJ<łćŮĘ*3rt#U–Lňă‰ů¦¤ÝqąŘ|#—Ľ3ć•’ mť…‰YŘ—˘i>ŇśyńuĆ´1Ź”…ňžőęĺ $Ă  B⨎~K°‘2K&® Î]>ç.~ŕ#żm«káüZgd išh´«6wˇçCż˙Jaxă˝Ç±­( ÇŦ‹Š ,K“9Étß»8š†‘ż?üuŢůŘĘ(˙7敦c˝ ŞQgÁőxE×»>÷;x/ř™b.ľKň3.´ŹÜ5<tźňĘ2x?\OTÔ=eó^¸kÜńéçâÓąMĽńĚ+ów QĄz_s¬Ź„IĘ !ń‚ĆçH¬X1ćcf…Ě+Ś”ő˘$1ĎdĘ›ăąLËs±,ć˛Ä,Ĺł(Ĺ c¶m岡pŚYš/DŚy;'LeČvcN,\ÂóN.<űR·ďäÂY™Q r'ź[ŢĹ Y2ËáTyr1YĚ÷d—ošäŞ4yR”¤¬óă)óD®ůćRć}ćٽϖo`ĆĽ‚r‚\*ä—Â.žTč›ÁâÉă2úú#öŇ1iďTňŹ ŽGřúý6ŽŁ}W‚-Ď»RÍÉ0wbŁꬺ×}¸ćŘ1wű1—m›ő˝żőůőÎb¦„Ń÷\[‰,«©¶be)đrz9µ)\ Şj”9Âqv°€˙šP[Ă»*y÷SĽďó!„eçűr,)ŮC€(*Ü»¤(Ŕq,™SâÓů„é„M,ćć‹x.¦1ÉL1EčEL<3™3dz“ç@/bČ\ĽpQRe˝¸±f—gˇ1d…čEL<—1ŇŚyVf˛ '1©ňڬ1ńĽťĄ ŮľťôĽ¦rÉ;9aJÖ‹aJŤ(S˛iLsę"fyň^Ě?ëĹVŐÂ,eťçĂ“«!ďăĂ7Mrrł<‰ssŚöŐ6˙} |śđ„_˝hx®Áý”Lo[Ö+Ź!«»ž GRô­764ę—Ěű|nÉ{ÖkJ.bôES=ábśÖqSL˘.-™d¦"sĘ|ŹKbVŚÓ‰ˇp‰ŹÄ$dE1+fŮšgRd%v‡‹us<—mf¤™LąŚ‘$ó¬HĘ|cŤç­VqJś/V¬b|Ä%EŢž§2dű«`Ě‘Äé3 ňN>!ĎŹ¦sĺ.^©˛dš'—2ďIť#±żÔ’ódrŁ, ůfŢŮ–9ď+\ľa’Ýűl7i*ëü‹¬r3ćeßçó߼†2"UúhČý”ۤČo$ĆlqÓ"F›G»ÍČĽĎ7Ő–‡Ó1©‰˘,2ĎłľK&ĂG••6~3הּ9wsâµ˙ŚŹ˘ í®˛3%X(§ťqF&Dŕôe> ض׷?_Ë2Q"¶mÖúýňµ˙E1dNĄ7Ńmż®sí±Á†Xýáż&4˛{žv‰p %Ď‘ńo„¤˝ ß”Ä;*·‰ڇDAbJř¤’Ge˘ľOMGťm/× _ kă=Ţ *Őô¤UĆž¨›y$†xAC =g‰‰ç”#1YŽľĚCĎćŁ/©Gb””#1ń"F/hl[­âŚ/\Lóv«(ĺ’wX…)ĹP¸˛¤Ä‹=ďL*hâEŚ8•PЬ¬‘•4YZŞĽ|Ł,6C1”:çZ¬Lćc˙Ő;•uţ…mâ¦y%ćfĚĘhá—őÂű{ŇTy1©·®=çE«CR-nɸ%“aś¤mß5Ź(ôčgJ(˙X˘ ˝±óó÷˙© ä;ęđ…@˙ź˘ŽáTš¦»ţ0_ŽÝ…Đu±űĎޤ E©µmŔóleĂ;­=pć.ś85¤( ĂđCçĆŹ>çríłőţĹßůş€"+í#žgí ĎÚiš–ď¨ůŐYCËíüú_„ë9ĽçĆ) E'ŕ€¤+Ww Śüź ‰’şýöţ?UČwÔţ÷F‡>Ł(Ć÷y8aú±é”áR DŃDm¤Č\ĘLî0ĆĚRD!ä.‰ĺ9BÔ´yC”xVEËVcće&—Ľ…Qf2›śË¶0’ićIŇłŐIQćmVeJҲm›U”$EN›mVq*—üUŚÄ˛ý«Ďe”˘ÜQ’ł˝Lłh’w—‰Q¬Ü]&L(GDI\+łË“É6óü„y®zÂN•o.e®˛…o ćyRn›ĺ›…ĎóŮ]“]ľažC7„fĚK–aľŃS˙–o:Ü4đŃ1GŹMš˛pq€t÷8g\\okŃV7řÉ`cC#ś˙äüÂĹ‹ŕŢ˝{âmŃřA6mˇC“ˇGzůͶ;âŚDQ[̨QQ -X@ś‘€+±j3ç§(ŠĄbÍ.IX(¦˘Tjj”9B˘ÄţßňĽŰaçŐY5<)őľďo‹ĘśL1Łm»jČś˘÷í2Ĺ MQĆ€Ž7ęy+SŰĐ­}ßކůÇŔĹůĄć§Ës„ÄźtÇp›XUá.Čs„DőNŢřôŘv9ë|±B˘¦ĎĚFš wU`XšĚ2˘.Ě,!$–7±dÎ$[7±Šž9VQrÉ[XE!d69—maĄxć$E‰ež“fĚł2Ł( ó6N‘bٶŤgEN›mś(eĚĽ()Š,€í^śŠeű#Ľ`Ě’˘ÜYíĽ0•9‹SŠtG€ĘÝĽ)H¶ S’$.Č•6!˛’ň6aŇ$W=a ß·\e ßL‘'%éöŇeGxRXÝ5މ›ůçĐM!‚ó’e¦ÂW?ëŃߦ—k%ŕýŘëŢď^–ĹÇżŻ~˛Úü~Ąl¶­/gÚXËhEX(°Äć‰OśĎFjⲠ™lČBQ E˘Úú;/»‘r?n$%üŔ3úz*ľ]°ĄµVkÜ1çn›s7ßóî(E%lÔPÄŔÝůĄ Š˲ęÝŘşé ´Ťě&VŤRZ¦éřtn ŻFUU›ľ‘–ç‹cfłB@˝«ËŇĘś!PŐ…™U‰ĺM¬2g’ąM¬dĚĘ|ć˛Č[XI!ę¬ |bŽ$d%–y.2ĎŇŚ"§Í¶mś$Ĺł0ŁČrÚlă)CvŘxARdYÇ#Ľ0ĎáTYRä;28ě|xĘ< SŠÖ¨î4ćÝ|8Rl OI˘¸ WÚ‘dWˇň¶đ¤yŢĎ|s>W%ćIIĽťśÝąçđ¤$dGxR0É5މ›1ŻÜě»4FůV˸xĘű•rŘöĘxO$ Î’á‹A%”âÍą9bŠaŕ¬äâ8EQć‡f1”T†L[(U•M2M©jěą/éňě|ŢĺůĚn¤Č¬Ş˝3e)"›f–Ě©ŞŞg9–7±D1ÉÜ&V1Í«ĚdĘ[XeFVg hEL„x¶ “Ę‘^|$äÉdWĄ-lšźČ=ß\Ę\•*ŰĂ“‘ů%1ßĚśóŮť]ߌĚ$ĺ°yľ!·ĹĹć§0c^Şśđ5· ‹_WĹÜ–Üş:x´—ß–ň†ęUJťUHTe7rŮ´3#„PÖó‹uŃŠ$ţ«ľžä—¬+ďYŻű)÷˛,îżäŹ]Wę·?ÇŁNŕżĐśy&„B­<üކˇŹ‡ň^śae\Śă1ÚĎţK~WÍZ_A!„Đŕżä÷ńhEKřF¸úÉę˙µÜ»„B!”'¬cB!´ZaBˇŐ ë„B­VXÇ „BhµÂ:!„B«Ö1÷>ů !„Z9Ô1#FjݵĄ––>XZë®ő]ô-Ýn\iiiŕZ`Y6¸(}°tY6ŤB­mŮÖ1ýď÷·ţ¦µápĂ­Đ­[ˇ[ Ď64·4|8°¤;—ŤŇŞ]Ő©f\ ”–ĆJ ˙%ż<#ç˝Ń‘ #ISVWa‡B­YŐ1ňŚÜýVwçÉNĎłŞ˘Š)ĎaOÇë';OĘŠ ‰Łzžřn˘Ö][ńh…Ăáđ~ěŐ>u:ť¨x´˘ôÁŇż?ˇoÂńoމo&l9+}ý}Ó—ý—SÍéŘá8?r^ËŤ˙Ţž ç·E„B­YŐ1cWĆ îýnăÄşu…ń+㦋9rđ™MĎ5…ľyĎzŹżv\‰D†>>Ő}jäÂÖ8ř*@Q”c—c±G“(|3\_W_ţPyůCĺÚ”‰ë@ý3őĐŘĐh¬Ą ´zÓ•––z?ň:ťÎň‡ĘGÎŤ®!„BYĘv<¸Î8QűQ”DÓE|—|„ëëÄ7*Q­%ÖŔ•Ř€MŰ+m¶¶úCődŽh#7gΞń<ëYĚa,Dń4xě»í·ţyëVčVҧß ŔŕĐ`×›]…ÜhŠęͨ˙ýţľwűŽ>w´µ­UÍB!„P~˛ŞcŘÄ™„’EűQűh!yF¦,ԙμ÷Ţ{ď˝÷žc§Cź“ŮÄEQî_ş‡Î ÉŠě˙Üßp¨!ďchmi5öÇ„o†Ŕ?ć—$©ý•v€řűľ (iŁÚÄ4Ő›®ýx»c—ŁĺůB0,üž!„BëFVßđUUU`ßE_ÓóMúDßEX ŞŞĘ8§><ĂmćH”ô˝ŰGS©V[w ®ůĹfŰV›kź+U=”ŤľţľşuIĹ)‘aŠJąőEJÚ¨VĘčŐ›6ŃX˝é¬śX†EQ–h÷Bˇő «:†eŘŽ×;şßꦊ©úýő0|q¸ű­îÎ7;µďcŞ ,Ăžř]¬ÝÄ]ă¶Z­íݶwţ±“eXyF&„p›®LąŞ\Euźę,ôqUL)s D,@ćHÁ×oĘ´z3˝ß[Í*ŰRvv !„Z“˛˝ďşĺĄ–žŢž3ž)¨ĽĽ˘üxŰń–—[šž‹ Ď´˝ÜÖýVwÓѦŽ7:b X`td”ňŘż=V^^^ű«ÚpxÁÍApďw[K¬®*WaŽĆŔYé„(Ś\!s¤éXÓÂ(ŠRîx8DŻŢ´ĆyF§ôEţ:`Ýluě,pk3B!´®äđĽşu—ý—§§§§˙5Ý÷}ŢŹ˝N§óDÇ Y‘[^n™ţ×t pětLOO;÷8€ŰĚť>súÖ?oÝşu+¸j\ Şo‹u‡ęŮż’ÔŞRZZ*ĎČ|ęíSíŻµ;î¬?Pżp©–—[ZÓZŕ›†˛¨Ţ>s°üˇňń+ă޳ޥhÜA!„ÖŹ"¸wďž(Ɔ ü—üZÁ‘ ˙%ż0%čŁ2ą"Â^çŢ««|źßVťŇŇŇó#獕B!„˛äżä÷ńhEKřF¸úÉęE d_ń"„ôő÷-¦Ńo25==ť÷šWÚFB!´PVuLúonMßß¶í6Űv[®K-rŁ‹·Ťöő÷ٶ.ęB!¤ËŞŽÁ1†BYx8B!„ň–Cź/B!„ĐŠ‚u B!„V+“ëJÂdň+B!„V “:ĆľË~˙÷!„B(=AHj1©c2ľô‡a‚íB!„Pľňy~ ľÝ!„B+öů"„BhµÂ:!„B«Ö1!„Z­°ŽA!„Đj•Uă»č[ęý@!„ĘUć:ĆwŃ×ôBÓ}Ř•uKľ‹ľŇyţKţŔWBČ}Ţ }îóvBˇĽe¸ďZ+bDQ̸˘‘ #­-­gk{Ą­íx[¶{·|}Í/6ç·l__Ýţş\ofßëÜ«…o'ľ}ĚńXăż7ŔéÓ®'\T1•ßždIŐOVŔčČ(Xŕ˛ďďŐî§Ă7µuµpůłË|ż¤;€B-FşŻÜě‹hmiýÇ÷˙ŕ·ň4M›Ďq„pâ÷'ęëę‡?ÎëÉ5÷Có‹ÍWC?‰D˙¸żă€‹˛DŔBCTBŔŐNE,tďE_Őá6E‘]»kÜEĺptQ€éMŹ\ôú?őťęí$sääď»EI”™Ł¸Ĺś¨lj˛c/Ł-tő“Őî_T ·#î}UŐOVźęîě˙p úÉę[˙Ľ•˙ćBˇ%–îK2ű"F“®€ ÎŻw€J,ťţ×t®ßĐBDh=Ö*J˘2§ąře—Ëź]¶m·°0"@„IA–d2î's2@Ń@T•˘!ŞĆ¶n˘ŁLđúDđ» ¨D P–lÇQJ,€ţ÷{ĹQ 6›Ť-aŕdÇIgĄ“%ěb†d2ÖdĄîMĎzDE´íčÓq?ĺrpË’T±•—$iľ\C!„V˘tßQză»čsďwg\Wş"F–a†9ýź§K,˝uëEeý%…ćšO˝ÓáŘ‘đú§ŹÎ´żŃ:üÉhöĄCVîEŃâ@”Ö†L `ˇIf–B•°D€P Ećç QBC¦óčÖ­[ţKľp8ĽvT:ů2ľî˙qŹü·OVdk‰u‘—–Ň×d‡ëöţ|oßö€˙s?eŰ;‘$…¨ľĎÇÎržDIO,B!T8™˙[;§«KéÜqF´m·ŃiWŤëTď©ňňňěK˙ż¬ČŽ6Q Ç&EěŹđC©ń€«ĘµŘ=ś§F Ůt18~וÍüľß¶%^Ę䪼ĽĽăő6űn»ű)·uKŮř•±‘˙öQ ‰’ڤ¨Éű}/¸Q/ü˘(JSb0,´ĽÔ$~3áţEUó±fB(ZÜćBˇĄR°>_sw~"*ŃŞ«ŐęŞr ţ×`Ó MŢ3Ţlľ§ý_ř»Ţ<ń+JŠŕ¬VŰ#Ľ˙sźłŇIYriLIŤ€»9ß.D˘ůÜaôŹď˙ńđŁ3 #D˘ČŻü !pôąŁÔjńc!éj˛ÎŢSoź˛=ÂK˘D˘ DIR9ĹýTť!u;rŃźÇFëź©oy©%©˛ôń8쎶WVt—7BˇŐĄ`}ľÉ⌠@¨BČĎţďź%ÍŘűç޶WÚ2Öăăţ¶WšÂ“a•(±A ESö¶ńńpý3ő˛"G&#I žţĎÓŮ\KNdśQ{k&eŃ.ŘäŚ.¦ŕřk' j_ĺŘăÚtľŚ§Š©‡}XűńˇĐťĂe8}ý®&;ŢqÜ˝ŻŞîŮzűN{řA™#mŻtB„)Qş-ľ ćqDŕ¬t6zŻ~y•ß»ÝI»ť›‚u Bˇ*dźoڱ‚‰jUŚŞ@áW•KťS…)AĄđwňśŇűçŢ–—Z2v¨hŠ’ç *Q6eQÉ(đŰxľŚ§hš˘ÚBĹÚl) ,´˘ČŐ®·jriÄĐöVVd‡Ý‘ÍüÚsŐĽ®+QőŹď˙!L O»źÖŠŽ“ÝouwżŐÝóvX`úÖtiy©ďSßÉŽ“p~ä|ĹöŠÜ š5Ů·߆Ăáć¦ćcÇZÄĐů‡ÇN§¬Čľ‹Ăŕű|lđżťO8ó8¨şýu˝§z÷ţ|ďôô4Ě10ţŐxkC!„R)dź/€^ÄÄ*ů ömJQDŐŠ­Qcă7™d_“5nŇj2XtM&L ŤžF-[7[Ă7ð÷ç{O˝}ĘsŘł5#„BF…îóŐlőŚ—™â1ůGľ [K¸đ¤É`Śvůj~ŁD«ET%Ň9x#Ěó6¦$»áź(€8Gh źž X–aJ8Ú56ĽD¨(’ëĐ1~—Ó52HńzH(-/Ms/´˙Ú8Ěw ey,÷ˇ&KŇűNŻ®~yö~;Ň㯗f$Ľő!„Pˇ¸Ď—¤íŹ!Ił%Ď™šžk"Ńů§Ü&nCë™ď†•h•†JT#bŕJ°çm[śÝ-H–Xվ⫪ʽżž˛»F”9"+2 |ßd“=<¶Ű+r«ĎRĽR{˙T÷[Ýć÷B1Öör›m‡Ť*Îúö«űR“µkůď0ôÄ zőá™ŢS˝XÇ „*”B?ĎW xB(ý?ďŁ A4·•…´Ľt4řÝüĂZ uqHëí%j¬Ö‘%‘;í6»=űpT­šSÜOą)Š:ńűvE çO}˘"QɱWşĽźvÓ[X%”%·ŻţT݇ě~«[{˘LřFĐä^č}U˝é=˙Éy®„ËöŮ}¨É _Ógó'1ÚmDó9‡R†ĚŠ˘ĺ9» âĎÜ#† I­Qçk'iJô_ tťěb)6§·heEŃŚˇú‘çíxŽ-¦h:öťűMש^I˘¤Ö]ë¬t ťqď«ŠÝ ýĹűUˇIb{•Ă+ –ş&3ňžő@ß{}IÓ=‡=ŘB¨ŕ Úç{×0“‚±É•ű)·09!‰˘Öő_gěbÖü%’¨ŢĎJTá°ŕ¬tVVć0Ł_·"DŐú…Q$úG RĹ,gĺ(ŠRďĆĘq¨ź—ęőŻwôžęąŕk{ĄmŕĂí^č¶—Űz˙Ň ťovĆžé·’j2„BhY˛ĎWž“µŰصŚÄ˙%QĐúLbEŚ 9T3˙ŰßKKËłťŰŔľËŢöëŁt.1Á+~Ł@˘D&*5~ÝŠ¨ ñV.öXá(B´5ç4„‘ćő¶­6íÁ-$Júßď˙&¶±‰”…â¬Y_Tş_5B!´, Ůç+N‰l1 ó$Tá!ń›^…Ün\â6s—ý—!Şćô#íÝŠ Ăd?ówßß>sĐuŕ(ðo ~=Îo±¶ka¬PĹ [ĚRPfDaR „Đ0V.Rľr+ĎqSÂh—Ť®~yU”D2G¨bŠłrÚHLN/ŚĽ5B!´\ Ůç;>>FĄY_T c 1ó_ĄŮżQ™+áŘbVͱ5´R&——+9v8ÎťúWOk?ú>>“i Á@ř»ńľ˙č˲meáë!űţŁŹ*¦¬›¬L Ă•pÚ8–ö&m@+×űU“!„BËĄ`}ľ}˙Ń×übk{ĐůfgVŁ  Š) ňăO¶,ŕŘé¸őĎ[*QMŰ–Ó ,T¬ÚČBŇë!)šâJ8†ačb:ök±eÉú=JfîOM†B-—‚őůÖŞs?ĺ–çä\x)ŠĘéÍŇ÷%ö¶Ł<ęmń,·b|=$eˇčâśG\2nâţÔd!„вȪĎ7KT1Ĺç˙Fž•Ĺ ×%K)Ë× äOÇ*Ćr!„Đôż–{B!„ň„u B!„V+“ëJÂüCcB!„V2“:F-B!„ĐĘ!ÉC-x] !„B«Ö1!„Z­°ŽA!„Đj…Ż6^G|}Ë˝ !„PnŇż©:«÷DngPeóňĹĚŹB-ŁŚEHVă1řĺ·2ĺWbrÜZyćňjVTTtďŢ˝ĺŢ „ZѲyŻ@¶×•đËoéčż§ö×Úł_Şç힥Ů„BhŐŔţ•Ĺ{Ö›Ílž#žĄŢ“»îÓ¦Bˇ\ałâdFĄÜŢß™7˙żÚU}. |0ĐţZ;·™ ]-ő¶ňSTTtőË«Î'śË˝#!„ŕ}רŔF?•ďȦUŘ*L§·w´÷ôö|ű?ß|gŠq×ţjďŚH”ä4šó€B¨P°ŽAö´űéŕŤ`ŇÄţ÷ú‡/ W>Q9úéhĎ;Éť=ĘŚÂoáiš^ŠýôŢ»wďŢ˝{?ţřc×›]˝§zG?]Š %1=!„ k}×1w—{˛PýduÁ×yâw'8ŽŁ7Ň,Ë|0 M Ś»ě&–Ű śHZÄôÓP8äŞqŃ4MÓtíSµŕŞr@­»¶ý· ĂUUUáp¸ĺĄ–ŕ×AwMÂíoü6jUŰőÇ.íÇţwűŮM¬Ě/ü ¸j\ôFšÝĶżÚ®ýľřmĽwČËoăišîŻßÉϲ,˲ÆÓ5˲ Ď6€rGÉfCˇë!W•K;KúJŠŠŠücţ¤śń<žp„B‹w_뢢˘Ŕ•ŔýÜbţ1Ń˙U´Ü{‘VĶ” ]uwvľ ¨łęôôtÝ:eąÖ]Űör›|GýŰhó‹ÍÂńwq™~ŞŞjő“Ől1;ýŻiUUűŢëí{}Ô—<čR±µbüʸücţ¤‘jýŰč‰7N@d2Ň˙a˙ĺĎ.ŰwÚ]OşlŰlęŹjčűĐđ…áť±z˙Ü;ú·ŃŽ×;ÚŰÚ>…BîýîŢ?ő¦?pAš[š)ŠŇŠŚôŇŽÎYéÔÎRšŐf<¦'!„PAä_Ç źvěvm(*ÚPäŘí>—ῆ5ą6@b‹·…óń„ÂéşAÓ÷%řÇüEE+˝|ŃË—–2,Ă‚zţŇş˘išÝÄ€ďS!„çůŔ•™#Ö«ďRüá4¦źúżđKSRĎ;=Úx>ÝkŇU˘6n¨?Pßr¬˘ö°ówť»#|#‰DNś<€ă¸¦çšţ: ĎPa«pV: !§űOsçÜăTĹtmŤžFí_žŠG+”;ĘŐ/Żr[¸Śňî—$©ăd¤żŕ•ń<žp„B‘gÓó§žĆ#Ť-Ď·üôăO?ýřSËó-ŤGö=ŠÖâđÓ˙űÓđ'Ăâmń1ÇcinlIß—`ßiżěżĽ4»YH —B•2Üî˛ďrřzřáG®°Uh#dÚ=P˝ďôj˙8÷8­śU_ÄôSé¶üćt勎ŢH{<P¨žŢˇ†-a@¸-€áÁEś•“$)¶¶âř2®mĐ;xď˙»wďŢ=uVýtԱۑ͆Â?„™&›–ťŚçÁô„#„*|ęůŽ|ĽăxgwgÓ MôFšŢH7˝ĐÔŮÝyüµăÚ@±óŔ´ÉŔ´Ů¸”év鍴łŇ9ęµZ­Çß8nşž¤ľ„ţwűůmĽÖ÷ Íü.XíJ.V`űÂĺĎ.k˙«ýŁO)WŤË?ć˙ńÇ+ꍬ¦xž'Q2xvpř°öOýz}~ÓO­[¬ D„”›Y~ †»ĐEI´Z­i—H-í#pL7ÄłŠ˘hŤ2˛l2Ľ'ŢŽÍźÍyXxÂBD>uŚď’˘ŕy6áQlžC‚˙ ?;vŘ6¤jĹĐ—ŞÜU™fë4Mת÷á7]OR†íŰD`BťU;Žw´·™ßp»bŰŚ…K‹AWpX–µmµiÝżt—m.k~±YűÎEQâ_̦źşöଛ­MÇšÄۢ:«ęĂ T1%Ďŕ~cçgŮÖ˛®·şŕ.·Ĺš7-~µYnČUă‚(xĎyŐYµńHŁ>3ULM|=şŇEń<žp„B‘OŁĚ(Ŕ•$Ľ©€łr ‰±‘­ó p-°°É M+†¶TĆ+Ö+™#é[:4®*»‰UgUžçSőO¬·öuNmýu+ýMo¤‡Î 2 4Műý~eV)}°”ŢH;ťÎĐŤř•;ÓOišľüŮeBiyé˙űî?vk3wďh<Ňĺ‰ÓŮ~ź?|=L?@W8*ęÔw˝ŮµŘuf˝!žçűúűZ[ZË*×îrŇtĽŢqĽăxm]ěî*ČxLO8Bˇ‚ČçyľL âŚh|é’ÖBˇ}óť¦Mzł…öٱC[*#I’¬›­iÖŁř` ˙Ă~Ű6›2k^ÄŔ|űB×»~ôaŰvŰéNŻíǶV«ĆĄç–c--ÇZŇŻ9ÍG¦2®Skî€ośĐî«2®!ăy0=á!„/ź:Ć]ă x?öźâ=ç $=$Ţd°!Ţd 7[dw1ĄŞŞ÷ś·î@]Ćő„¡ć›oÝşĹóĽĚďű{Ę·C»j\®—,ËíŻµ×?SźÍ 6—Î}{íB!´ÚĺSǰ›ŘSݧNvśd¶áP }÷~wćůBˇU+źńv{ŞűÔÉŽ“gÔYUťU>8ŮqňT÷©¤k@®DÁ{ΫΪŤGµ‰î_şË6—5żŘ¬U6˘( ‚`\J„Ŕ•Ü–em[můÚZ°"‡pB­yyŢwÝţjűéÓýé˙Ů?űŮ?ë˙°đě`ű«íIłń<ß×ß×ÚŇZţPyĂł ÚDš¦ý~ż2«”>XJo¤ťNgčFȸ”:§¶ţş•~€¦7ŇC熆?ÉęÉ4kĎ"‹ő<…BhťČçş’ĆÓŕń4xL?şwďžž[޵´kŃŃĎóŁGS-UńHĹDp"ď[°A!„2Â÷+­PĆ>ßś`BhýŔ:f­Á[µB­XǬMŘç‹Bh=Ŕ:f „BëÖ1k 1!„ÖŹlďWň/é~¬gîŞB>#‹„BëGţ÷]Ł%˘˝·!˙Ĺ }ľř<_„BkÖ1+‹çů#yr…W—B­XǬ ®Ç]6[V×ÂápšO±A!´N`źďZE Bˇő뵋„BëÇ2×1M .+Ç,ď>¬1ř<_„BëGžý1M .㏪ BD¦kÚ(~‹UśQJîöV/Ľş„Bh=ČżĎ×? (šâ73ÎÝŇŚ,Ü– ·oć\OTŚŽMHXǤ†E Bˇu˘÷+•Ĺą( @ĂţĘŕ¤dßÎűŻM9âÜeăJX5 BDż†»Ŕ°ŚsĎ1¬q%M ®Ń± ITŚ™a)çNDZ Оo,č®±@íăŽPD˙:l„·mĺi @ŕ»Př‡%Ż˘V>,bB­¨cŤ”cÂŚôFÚ¶Őęűb‚R÷ » )ľŻü”…Şű…ťĽ!¸÷9ÂÁw) é+ĺz7€{ź]™!Ţ ˘f#ľKÁ¦×čWZ•Ă8á‡/”YBm đr 1!„ÖŹüżü]•PYpÄyôŇ™Ť]ë ~'(˛bĺz#ü<wÜ%ádŰjUfTš†đ Q[0 ŢjĄiÚ÷]Pk…Qf“/$‘(Űv><)*˛’~më>Ď!„ĐúQ€ţ…Ô(š˘@oČ%DĄiš*¦Ő»@îfînˇ(łňEGfÉčŘ„c_˙”CžU×ÂŇ%÷ăX›đęBˇő` ď»V Ц´)ŠVU˘*˝!6ţ‘µ16‘fŁÉ<:IT|—‚Ţ eFq=î(Ř®ŻrXÄ „Z'–°Ž‘fuVµďŕ€ÚHŮʬá$J đĽ•Ú@ąöžÁ8†eXFź(H’ŞŞÎ]6f#Em âŹ™ąéa6RÖM •Č ŢľE Bˇőc)›cď‚ď‹ sŹ­éK»_)xC€»řZpíŞPwÂřw!í^$¸)8ěĽmÖęż®­aă‹ď˛Őďwj-8>1¨Í骬 qĹ4ČsŞ˙«‰%<–Ő#c%Bˇ5#Ď:f`ČźÍGĘ,ń] &ÍţA˙ Äfžď° ^‚×…¤5(˛ÉâĆ9G>Ďo˙×°ôe >ä!„ĐZ‚7+Ż#xűBˇ5߉BˇŐ ë„B­VXÇ „BhµÂ:!„B«U¶}ľM ©_„„o„F!„ňă1!„Z­°ŽA!„Đj…u B!„V+|Z×đÇ!´¤ü_Ą|@6zŢîI?Ö1h˝sŐ`;B- ˙%?xĎzó[ÜsÄ“qžÂ×1EEEWżĽę|ÂYđ5#´Dxž_î]@ˇµ,Ź;sE)«Eň쏽8ęŘí iş¨¨eYÇn‡VsiH”göŹů‹ŠŠňŰB!„P*ůŚÇ‚đôŻžîëď;zř(MŃâŚ8ńÍĂ0©ć·ď´_ö_^ÄN"„B™Čg<#»j\EŠj÷×@đ»`µ«Zű¨¨¨¨˙˝~~ϲ¬~ÁĚtb`<ŕŘí`7±ÜnŕĚ€6‘ßĆ÷żŰĎnbý—ü'~w‚ă8z#ͲěŔůž„B­VůÔ1Î=ÎĘ=•§Ł˙Ý~AÎĐţj{ŰoŰ®~yŐ÷wßÄ×IźöüąÇ{ÖŰňRKó‹Í˛,›N”eąÖ]Űör›|GýŰhó‹ÍÂD&#ýö_ţě2ULuwvľ ¨łęôôtÝş<ˇüÝ]î@!”gźď|řë€÷cok[kYYYËó--/·Đ4­}ŢőfWíSµZV%i#]ov9+ť|ßýVwŕZ@›3i˘"+„žçW`-±ú.ůZ¶µ@çď:v‡x[ ôüĄ§ĺů–ŠG*ôMŻjţŻüŮßźćŢď^ŇťAiřÇüŐ®ę{÷î-ő†>h­ťŰĚ…®‡–z[ůÁľ~„ĐňĘ÷~Ą ĐôBSÓ Mę¬:rq¤ýµö±+cŁGµą-\šE9Ž®„EVL'j]Ę˝ďôjź:÷8­śUËl «mâ˛ďr×»~ôaŰvŰéNŻŤżIłĽ9-›[ŃR)--Ť˙`Űv[ç:ť{–ęěů/ůív»ö[K2radŕĂૠŘwŘ[^jYŰĹŮč§ŁÎ]Nv“É©¨°U„Â&•J{G{OoOĂł ß™¤Ö{«Őę9ěéůS†ç4JęëĎ(Íy@ˇ\-öyľôFÚÓŕé:Ůĺű?ą=OLś€ß›NäyžDÉŕŮÁá ĂÚ?őę“ÖŕŞqůÇü?ţřcĺ•őĎ$şz‰™L“/Ő媯żozzzzzúŰ˙ůÖjµ¶k-Čž›jü÷Ćđdxáôţ÷ű[ÓÚp¸áVčÖ­Đ­†gš[š>\Ë}NO»źÖŠ6Łţ÷ú‡/ W>Q9úéhĎ;Ée„2Łđ[ř%nôŢ»wďŢ˝{?ţřc×›]˝§zG?]Š %1=ˇuĄúÉęŚS˛”O¸čúC×Ä×ę¬ âmŃ{Î[ą§2Ű壽îµn¶Ć‡'şé.Ű\¦7ТÔ#BŕJî˲¶­¶<ŽgĺÜ5nE‰ŤŠM|7Që®­x´Âápx?ŽŤ “‚§ÁS^^^^^îi𤙳´´ÔwŃW˙L}éĄÚ‘V_664žřý ăvĺąű­îΓťžg=T1ESžĂžŽ×;Nvž”Y[UŕZ@_­–M7ęt:ţ:PńhEéĄĆ­8ţÍ1ńÍôžęu8ĺ•—?TnÜU}ýF¦Íă¦-ç:ÓOCá«ĆEÓ4MÓÚ•SW• jݵíżm7.^UU‡[^j ~t×$ GńŰx¨ýUm×»ŔŘä>ć~\5.z#ÍnbŰ_mךuřmĽwČËoăišîŻßÉϲ,˲Æ©˲ڏrGÉfCˇë!W•K;KúJŠŠŠücţ¤śń<`·>BëV˛ —…S˛—OĂ”0á›áĆ#ŤüŠ*ü~t$Ű˙’«~˛šŢHűÇüŁ… ćišöűýʬRú`)˝‘v:ťˇ ŁîęśÚúëVúšŢHťţ$ĂßÔČD&ľ™č˙°żáp9rđ™MĎ5…ľyĎzŹżv\„úgęiŠţvâŰ[·ni_¨¦sj«ěz««ĺĄ–ż˙íďcźŹ…o„µßËŕĐ`×›]Ć-Ź]hr‹OÝ:Âř•qÓťMµŃH$2ôŃĐđĐđ©îS#F´‚8đU€˘(Ç.Gřf¸÷Ď˝Ă#Ă·ţy+ô}H/ÎrޱÑ´‰ĐőĐÂćńT-çÓOUU­~˛š-f§˙5­Şjß{} }ŻŹú’]*¶VŚ_"‚ĚĎoMžÔ64ú·ŃośC“»}§Ýő¤Ë¶Í¦ţ¨†ľ _>Ń›ˇ÷Ď˝Łíx˝Ł˝­}ŕŁP(äŢďîýSoúAhni¦(J+2ŇoH;:gĄS;KiV›ń<žp„ĐšwůłŘŁXŞź¬ÖţIšž“|úc*lޡ”mĆćG='^ö_Öţş4Z8‘çy˝áfá +©Xüĺ©ĺ°Z IDAT•®úÉjă/;ż_°©Ö–Ö֖ص¤Ž×;Z^nß%!ĺŪ cXK¬+ÎĘI’Ôů‡N–a€/ăSÍ©}ÔţJ»ţ{ÔFVLÉ32Ě·Cé´S=Ŕ1ÍFŰ^iłí°ń[ů“ż?¸p>îő-l9·ŮbC€¦ź–ńeŇ”ÔóeŹÖ’ţaÁ*Q7Ô¨‡hlT2 ­É=p%‰DNś<ˇ=ő éą¦ţ÷ű»ţĐĄÍPa«*%BČéţÓôFÚąÇüÚü"N٧±ŃÓT1ĺzÜuőË«zg[š Uî®”$©ăd¤żŕĺ˙Âźţ<žp„ĐzpůłËIŁ/yÇáű•V(Óa·B•2}ý}ÚŕGíŻjýWüZ#ĎČ”…:óÁmÇN[ÂjKś5ˇŕ0ťSËÖ-Ölv@›_śŤkÖ¶eÚś~ŁĚ&(Šr˙Ň=tnȶĂć˙Üꏧ´=??tľ÷ťŢjWuŮÖ˛ľwú»’‡at¦ÍăiZÎaľęJúTş-ż9«whfP(sŹ—vČÂmć[ăµc”$)¶¶âx)@oĚP z=‡<úh– ˙fJljŽŚça­vë#„˛a,eóívżëÁ˙´ď°g3qť+`­š’úŢíŰëÚŰ˙~ËK-ÜfŽDIß»}T1ĄĎ˘]¦mäCc:gNŞŞŞŔľ‹ľ¦ç›ô‰ľ‹>°@UU•qN}x&›ŤÖ¨k~±Ů¶ŐćÚçŇ«çăNçăNY‘»;»Ź6†ľOwł«ĆĺŞqɲÜţZ{ý3ő˘(ę-çƲ@o1ýTë–"‚ÖŕRpZwĽ(ŠZ…!J˘ŐšUůh¬Iż!¶UîlýůOFâíŘŻL+jÓź‡…'<ĎA­BÚ7Ý"żÝ{żR®n{ą­ű­î¦ŁMotÄČfŁpďw[K¬zŹŽ2§ăxyEyůCĺľ‹ľÓśÖ¦¬;8q#ążĘ´y<}Ëąé§4M_ţě2Dˇ´Ľô˙ý@÷»µ™;Žw4iĚűýőqŔď󇯇éč GEýú¤6ę‚1ŰĎó}ý}­-­ĺ•lÓńzÇńŽăµu±»« ăyŔn}„ĐâŔ˝{÷ôá\˙%ż«&ˇßÖwŃçŢďÖŻ‘Ł‚ÓO~űkí޳ތCë˘$öţą·çííWłô;x?Śśé:ŐEY(W•«íx›6*“OÇöíÄë'2Ď ľ‹>WŤ+}+.Bˇü |0ŕ˙ĘźÍWŰBú—ťq˘˙’ßsÄŁ­-|#\ýd5ŽÇ ˇîPÝÄ˙Lt˝ŮĹoĺó.b„0öĹv§BˇőďWB+HŇX`®!}ý}Ć–d„BkÖ1+Nި ŚlŰm¶íŘ.ŠBëÖ1+Ëb^‰B­7ŮÖ1ř\‡ű ©› !„Z–îRCVuŚďbnď˛Fhń_ň/÷. „ĐZ¶¤—2×1kćÎ^„½BhI-ő_łxß5B!„V+¬cB!´ZaBˇŐ ë„B­VXÇ „BhµÂ:!Tľ‹>ă eó#Be ë„Př.úš^hŇąB({XÇ „ ‹„ĐrÁ:!´(XÄ „–QÜ»wO˙{ÄÉďŞq-ë.!„B™đ_ň{Žx´˘%|#\ýd5ŽÇ „BhµÂ:!„B«Ö1!„Z­Ň˝ďÚwŃwßö!„BČTš—f§«cŇ/‰B!´ÔŇŹŞd¨c ýµöÂí B!„ÖŁž·{´S]ˇ/•Jć:Ľg˝ŮorĹňńŔZ9´ę¬˝ýÖŢ%Y󸺬ę_ÇŞŢůĹÓßř¤¨,φ¶lzYŐ1°ÚT%Jńý_íÇ‚Vťµ÷ŻßÚ;˘$kţW—UýëXŐ;żxĆĂOţ(ÓŮHł¬ŢŻ„BˇŐ ë„B­VXÇ „Bh™U?Yťß‚XÇ „Bh9iEL~Ą Ö1­-Ńĺބк!DBČ"Wb,_ň(e–§Ž)-- \ ,˦ n- Zíץ–.÷^ „Ö‹˝Î˝ßM,f —\K™ÜęŇDŹVtuvĺ´†Ľů/ůĺYߍ‘ # wÉáp´ţ¦U˛YáĘ9–Öc­I;&D˛:´zů>őŐşkËËËKKKË*Żu׾*d5¸(-Ͷ )Č(đ]ôŐ×Ő—?4PżŞMSâ˙,µBŕČ…‘Zwm饥–Öşk řćýlqOŃbţ3ž}JřfŘtćśöęţ(ČţgssúŁt?w>Ë5'Ió7Ďrýf/vYű_í}JörŹéëžžžžţGčŻwĽ÷ţ{ţKţ\W’‡Ćo Oš˙šµ]şőĎ[§?8-Ţ«ź¬Nő/„é‚Ë~,#˙=âű_eµŽSbsSsݡşĐ÷ˇéM_ýňjŰ+mT1UŔM8v8ÎŹśĎoŮüţ@őţą·ąĄŮý”űŰŔ·Ó˙šľężÚô\EĄ<¨4˘—Z~Ř˙~ëoZ7Ü ÝşşŐđlCsKóŔ‡Ů%ýlqŮś˘űó—X®{µŇ¤Ů˙Ś'p1” ˘€'?ýß<Ëř›5.ą1°ëJ,ĂÖ¨EQţöŢ?¶‰+]ř,…«™UĆUşň XŤQşÂ.­°—^Ĺľí1PµT/ aC%’´úŞM˛U7I+g«n’®vSµ$­ v*ť~UYÁÚ\•SuSAcWđĘ••'˘(¶H”± Ň|˙8a0öŘńŻü°9YŃä™óăyÎśóĚ33çĚ€^ŻübPý¬Ú˙ż~v‚­ß[żţ÷ëçĂŰ9€ĐĎ!t­¶ţ÷ëĹBĘŰě˙c-fËúőëׯ_o1[ ~o=ě7ďďxŻ#ť>D%ˇÝ¬u9©*ĘöçÜî¬,Ż-µŰj[ßnŤĆ’áÁz˝UíüjţŐ‡z˝~řëa˝^ż~ýzç—Nß%źZ­^˙űőb$ř1Pg¬S?«Öjµb.ĚŠ‚ý7 ¦]&˘’€  ´a»A»I‹öJv¤5kÖ8żt˘ţ0|ćá­…T!"đS`·i÷ü¶T—Hěä’Jć4 ¸I®Ż§ŻýťöĆ×ĺUr¨z-mÚeBFĄöä¤Q ©!eú˙Ö«źUŻYłĆwÉ’ăQ´eÍďÖ$şíj?¤˝ăť“Ń;Ńîş»:»,ű,D%AT––öwÚ;»:Ńȕ߽wwăÁĆŕµ ó”łíí6üj˘ß¬×lÖÔëżĚţŮ?±÷˙˝żá`Ă‘–#bÔ+)L$]—xŘÉ7k3Tšĺ€şrĺ v™$÷¦öäÄQ ©!;ĆťF˙·ţŕµŕü‹Çç u<&ÚŇÓÝ3üő0ňąţ˙ő‘Ůşě ĽtůĚ%7×´ËspĺrÚĽ’Clج‡­çľ9wéź—B?…$ý[˘°~Oý‚v%:±zކ’Ze.ayÉC˙tgÍ& J éĎĂĺfŁ|čçPß_űÜĂîđŤpđZи]ú‹ÎIEeđ<Ź´ŚÔ@“4_Äţ±ť¨ _k,ĐöüČ9Ž9b=‚%ţ—ῢżF]Ă.ZAŁ]-o¶¨6Ş?&&&¬G­(Üłěł8żrú.ů&''[ßlXŕ[ţËţÉÉÉ®÷»ä””Ś2W ĺUňřLVÓ§W-Aô˙˝ßsΓô¸]˙Ľ^NÉă3qĺZe˘EÖŁVeµR÷ś.Ź÷v÷Ň Z·Y‡Îaž‹žx<®X§üŕ㼢JáżŚç Ż<*`dxÄzÔę9ďůŻ˙ţ/˝^o˙Řľŕ:ŁÖ¶Víf­ő5+ĚÁŐ«W3ÉĐ%P'Ďđč‘Í€BŹŐé*ZroşžśACß%_ěN̲ď‘k>˙ţÔńhKýžúřLÝ ůüÔçIŮ‹n ú7Ă«ÓÓŢúf«ˇvţ:X2úLÂř˛1ť]’N¬đž«†+Ťěő_đ,@¬žo+Iľ.7ĺ)Š‚ <1ú9D„ĽJžUQŮyÉ–át …ĐU®–r“\ć_–ĺdű}%‘~{żi§I2ő$“Ü$]VĐ“w&ąsE-8x€»Ă%fĎn’S(٤\9¶h7k›7·ľÝŞÓéDˇó+çĐ—CJFťy¤+SrJÜNšT˝%*Ď?ű|ľŘMÚtýłĚT€eźĹ˛Ďź‰{.zl]6˙żü™?ś¦ €śşőť*TÉ=?C—@ť|A˛PHn’Ł×Jôöt=9†Ń;Q‚ ’F™äxL´… ăKơ3CŞŤ*ß?}=î)šUrŕîp‰Ă đ C,ťáŠuY9(‘ vI:±Âz®®4˛×Áł€¤?_ —›Ťň´‚v ąú>ęŰjŘĘT3ýőKŢc“(* Ď#}âK:úrHY­”űČćY’sł`&äXąÉůĎMrŠ*QIÄfb0P’—>bä…r±˙fó¸ńxÜsŢc|Yú&›+Ć–Žw:<=GŢš_»Äţ?¶­Ąměű1z-í˙Îéź—˛±†^KÇçâýď/î¤QĚâAT¦]&~†okO~°(y9‚Ľ łŽ‘Ćç’;d]"Ë…nĹ~9ŘńNň´{˛¤†žłžx<ꉕ÷o]2JŽÇ¤ŇL»LM‡šTŐ*ĂC6g”, ¬­­… đśő$Ţ9÷śő@ÔÖÖ&¦ŹZ~C8™ěJqbŮtŞŠJĽÖGjSTVQÎJ úgw”ôçůŤŻ˘(Ż^Ż^ŤE»»ş÷7ě^ ć”=ç‘hNg-m-íöŹíÖŁÖě(â÷®‹˙ţýf=Ă0čn7É ~9hÚcŇëô0Ăg‡ă3ńĆ懎€¨$®^˝ú9täŤůó·áb­˘őŹ­Ü$'ŢJ‚ bżĆ2U<hňQK[KéŮRýďť:3q“\ôN=oĘća™q»QˇP´ţq~ÖpôN”ű÷c÷yŐ•Oŕ‡@ß_ű?Đ1ĺ&ąáłĂşÍó·âR;Ňţńq[—Ťýl|&ÎN°_ ú.úŇődqHj¨Óé z?î ýjjnBµHŽÇ$M µ‚ ş{şÍűĚE4PNÉŰßiďţ Űů•3>ŹĎÄť_9»?čî:6›=ő¨ĺ4„%}B˘0»˛;覝&ű'öŔh,Ú×Ó§Ú Ęććń®xIXzý%ýy~ă«pĺąs(»ś’+«•DEVQÔžçAá’-Ýé (95đŮ@wOw®/Źŕ"p5«7Ó,Â{đ*Ŕ9ä Ý ­WŻßúâVăËĆŽ¶%Łěů°§őíVýëŃśpDËŃ–îşŰ˙Ô.fwąaţđźP?«¶˙ÝŽÄÖŁÖ#˙÷HҢ ÄüÎß­ijnR=Łň^đ"ĎRr¶h7i[Ţś÷§ú˝iŹi‡iGÝ+uúçőšMšşWę˛Qxdx$Ź˙á?˙°~ýúşWęBˇ[!ů8 §äěMöČG֫ׯYłfë‹[•딟  ˝ vďÝ˝ţ÷ëŻ\ľâ<ĺŻ %…Ź{—Čo@uĽÓŃ˙·ţ+W®l}q+zyĚ•+W”JeşžüpHi(Ż’÷÷ő~âó:cťő5+TA’ă1Ő^ăNŁ˘Ja¨5×@ëako_ďç'>_˙űőëŐëŰZÚ¬G­ŤçŻdRŹZNCXŇ'<"Ě®ÄFXđ wtv_66˝Ţ´ćwkţđźMÇCŽ…KÎ芗’eĐ_Ňźçĺr W>6kűSŰzőúőż_ď9ë˝Gf2{žÄ!)1ĐŇśÎÚÍÚö¶ö¦×›˛źÔRDd ÇÍ×í»č3lź'žłăNcëŰ­ÎSN1A‰ÂMrhiCŘ‚)9 ď~kÖ¬q »ô5ú…KĂŇ ¨9ÎDźV?=ęÍňYłĹlQ=ŁJ}• 8|fŘÖc#*C­ˇĄ­Ąh×Né)Š]%JI;đ’Vľp$ÍĎ2®@y{?ěEŃú.ú,ŻZPŢĐOˇ­/nĹßWÂ`0+ŽĐϡů»î3ŃÎ?uŞ6¨˛ bŘ öŇ˙\ĘrĄR!ößlÇlĘjĺ1KfSrä5ĎÁ,-ýö~Uµ*ayŤE;˙ÔÉţ›%*}ŤŢq*«»îŹÇűíýů­ČńîőbłÄva0%Žc0@ňséŢ;Wčkô^_ÎŻ'Ő•jCĆvĺjS8řąÁ`0Aź_Ĺq Á`0ĺÇsÖÓřzÎ7ČöąŇ˛,¦Z$ĘÉLÉQ~ÝŻü,J˘ě ,-Júp”´ň‹ bňXŇ•USÄ÷/;ĺd ¦ä(żîW~%Qö–%}8JZů±Ľjéý°7ÝŢĽČ&ŽÉňĺÁ Á`0éH¦ÄžÁ`0 fąH bđ<_ Á`0%q§11Écž/Žc0 Á,3y?]Âq Á`0ĺ¤)28ŽÁ`0 łlŕyľ‹‚L&ó_ö/· ¦ä)'gRN¶`VË0Ď×}ĆÝřzŁúµď’/׼+÷·ţ=ąš”Édrą\ŻÓ‹vĹçâ f÷]ňÉd˛EÖSž”ŮP‚r´( IůiŢb¶«Iš¦{?’~=F6Îd)áyŢb¶Đ4M’¤^§†‚óň’˛EňpDŁŃƆFdšVŁM튒6(Ěú˝őrąś$IµJ=r~ ˙ h5Z’$µĎiŮ›lŢ…—Ë0Ď—eYÓNSč§ĚĺšuĹa{ß¶ŰĽŰ´Ë G„{B °µ‘} šMšüľf‡Á”ÓPB”źEIHŘt¨‰ă¸©ŰSŢ ŢÎ÷:Ý_»—OÁ¬™ăc8ćďňô:zży?—–-’‡ŁőíVí&-Çqü]ŢĽĎ\ż·>)—¤Ť ó ĺÍ–H$ÂóĽi—i˙«űîCť©ÎzÔĘßĺu:]Ý+uů•\şôtI„Č'âöŔ§‘HDĽĽ’»J…H$=öHî×iWí¶Z¨ă#ö˙­ź©fJ‚Ş˘A@AĚŇ)Ť);Ę`(%Q~%‘hŕÔí)đúć˙m>Ü\»Ą65ýŔŕ€jŁŠ ćŁÍHľ®ÝV‹śIK[‹pOč·÷S…\®kŘĄÚ î ‚ ŚúG5›5TĄX«@nG„öÎv…BATE |:Tcş˘$qśt@bKŞcaüÚxí–ZŐ•Bˇ€sžs ŞťIýÍř’Ń5ěBŰ^ź—©fKÚX °@ý]Ă.ŞŠaüÚ8ĚÎΊzŽ}?V`á+ 1ş00'ţ‹âŤ$I$ Ś™ĹhDŚRÄ”Ţ ŢÇ:Žqśt@†9ç97ęű“×çťş=%Bχ=E 8ŽÁL Ą$ĘϢ$ Dntöî,úwŕÓä’Ň3 ă˝ŕE‰]§]Â=aćĂÍÂ=!‰0ŐL{g» şçuĆĆŮŮY†aĐÉrjjŠ˘(ä¸ÇcPáat ß ‚0;;‹śR©EĄŁá`îy]ţ¶H9ĆŮŮY…BŃ˙·ţů\pÎs.µó ©żŤ~;JDĂk şÝřµńÄÄ’6(Ě[óđŤ°kŘĄ{^‡‚Ľ±ďÇÄÂgďÎ:îĺDş8F2É>Žy|çůĆb1 «čt lÇlu/×éuz1±ˇÖ RÎOóJĄI0ĚăLt& äjýKÉ)IĎ`;f3l7¶t5:ĎyŹ˙;˙ÄÄDGg¬š¦6~1ÎĎťľú¶ľ¸UŻÓj ŕ9ď‰ÇăJĄŇŮź‰+Şž‹9%‡ čý¸7x=H’¤üIyjŤ©EIâ>ăö\ô ŹĎäg H9Fß?}“““ Ż5$fĚFíÂ!* …B …š›h­d”‰{%m,Pźžü4ßń^G绝A¨«Ő Ú¨"* ű'vžç»{ş _)S‘•+ÁăÇPż>JŻKq?Ô>§m:Ôôů©ĎW9 S Č)9đÓ<ú76CŽ% љР:Ť±·X é‡ÂÉÉIP>ĄÔlÖ\ůß+-m-hrP}őˇźľFŻ ô:Úëń†®‡ž~öiµJ-ą€(µ¨Tś§śÝîřJĄ2o[@Ę1NÜš * ’$“2.¨vđÓüÖ·öď÷_ö{}^˙ţÝć݉ $m,PźŞäjŇ9ä ^Ň4]gŞ’$G†G†ľúö(üRĐŠü /-çůćÇăÇ kű'ö,ÓCÁ¦CMîÓnçłĺ­´®Á<>h6iŕĘWĐżH’î§ ĘuJHřf7ɡI$#gGâ3qÍfM÷Ýh—R©ŚĎŧîŻÝčWż« Ű ľKľ©©)Ý şÔ©¬’E%á<ĺěčęđúĽb\’ź-’ŽQń¤">Gç{–eĹy¸ Ş] Wş»«ŰV†ZC˙Gýž<˛WŇĆ…ęlÜf ýBۆí†ŔŐ@0Ô=§ífm…?&<ľq ˝Žn§˝űîÖ?¶CA~šgo˛öăvq \±;1ŕ&ąčŻQ÷7DŁŃ%ŐÁ¬0ärąů€ŮöľŤçyö&;ôĺő kşÄÁPđĘwW,,ú=SÍŘ>°Á}ŕnq'4ň<äŤ#ýÇű§Ă_Ł…0Ć—ŚĚZ¦éPň6DZ,˲¬˙˛î\.WU«R+’,*–e÷7îďhëÇăÇEŤćm‹¤c4l1@tvuŻ-f ä‚jŽŞZE„­Ç÷çůᯇu5:°6[‘n’6(ĚOUÔü4?ôŐR‚ˇ ܇h4zä­# Ä;v…r™ç«Ú "* ‚¨$Âáđ’O*&Ž“]Ť­µ¦Ş(ÓÓxp\@sÇLŽóČĚĚP ø†]šÍŐFžç‹É›2JB9Z”„¤łwgÍűĚhZFOźÄúGä[Çp8çgn†o„k·ĂöůIažłăN# 1 &oři^śZęälË}ƢOüö‰đŤ°ň)ĺÂé1eŤi´ľÝę<ĺ\pZ 7ÉőýµŻ÷Ă^Ť ˇď˘ĎňŞĺ ýÚúâÖŠEUÁ`sĘ&¬m ^Ćb1ÍfM|&~¤ĺjŁ 1T2¬łÉ Ç`0 ¦Äb±¦ć&v‚%ÂđĽaäéI‡ÇË«–b…ă Áý úŕőŕrkYąž7¨TYÍő…B ¦y|×+a0 )upÁ`0 ¦TÁq Á`0RÇ1 Á`JÇ`0 )UpÁ`0 ¦TÁq Á`0RÇ1 YűË­“ÇH#“Éü—ýË­Ášď’Oö˛"ęÁ‘Üâžç-f MÓ$Ięuú`¨äßŘč>ăÖż 'W“2™L.—ëuzß%Úź‹/ŻnňĆ}ĆÝřzŁúµŘĺJťňł(‘ĚŢĎ~Ü.“Érz‰mjs-ŞÍҡŤś‰ţMÝ^Hö·ŔżZŤ–$IísZö&›š‹źć-f ąš¤iş÷ŁŢ˘‹˘<{“•= ţHs–äx?fŚ;ŚápżËÓëčýćý‹ŁŐa{ß¶ŰĽŰ´Ë G„{B °µ±Üza X–5í4…~ Á˘ź Ź IDATÜr«R$ĘϢGHďý|—|˝íÍŐuH4× p°;Ś;®ţt5u{"Ń€÷ˇÎTg=jĺďň:ť®î•şÔ\M‡š8Ž›ş=ĺ˝ŕí|ŻÓýµ»paQ”W2ĘńkăâĎ´Çd¨5äWřă ‘8N:ÄíO"‘ÇIT@ş˝+źH$=öHî×iWí¶Z¨ă#ö˙­ź©fJ‚Ş˘2¤ż6^»ĄVµAĄP(ŕśçÜX„)EŔ{Á»ÜZ“ňł(•Dż6NQÔřµń\‹J×\élřF¸v[-ňB-m-Â=Á5ě"* ô B˛–ÁŐFAÍG›ÓU»Ą‚hył%qŰëó˘3… ŁţQÍf UE)Ö*D7ŘŢŮ®P(J‚˘¨Orm„BHlŔńkă0;;+ÂÔí)ű~,11z}óé›7×n©-PX,ĺ Ś)Ö*¦¦¦ )|’]Ś~;šÍĹ!该Ey/xˇů1ľ˙ńéjtyg_v|}`9ö“›­lmy«eôŰQĎ9Oŕ_P=Ł řü4ßŢÖŢÚŇš.%Ďó[_ÜZż«> r‡żĹ‰Á”˘÷ă§ůşWęú˙ŢŻ~F˝HU<Â}0ĽhP=Ąâ§řŕµ űkwGWGý®z~šç§ůp0LQTË›-’ÚşlýőŹ|3rüăăî3nɢĐ3ŽĎHďG˝‰Űb!Ńh´ÎX×r´%úkt䛑¦CMěM6x=ŘÝŐí˙ÖĎOó‘HÄ´ËTܦȞx<čş=–ô•Á«?^Ýćů†ŐnŇ^ýńjÂâ›qššú˙Ţ/—Ë‹_x9’gă>ăö\ô8O9‹«ÍR‹Ĺ€®JűŇvĚV÷rť^§j ň'ĺü4ŻT*‘D2ĄďźľÉÉɆ×Ý łä$zżÝćÝ ęvJ<ż(V‰řżóOLLttvŔ* işń`ăŕóűîCýŢzÍFŤíM˛LŰ1›a»Á°Ý «ŃyÎ{2•ĎyO<W*•ţËţřL\QĄđ\ôČ)9T@ďÇ˝ÁëA’$ĺO.ŰŮWµQETöOě<Ďw÷tŮ< :r5‰ţĄäT,+PXt+l=6ZA×ďŞ/zÉĺJ>qŚó”łűĎÝ@©T]ˇ%˘(ŕ&ąt čuÉ!ÎŕgÚç´M‡š>?őy†”·&J‚$Éâ)‹Á`V‰Ţ/x=č9çi{» ÍĘŚĹbO?űtŇÜOűq;ąš$W“†íŮÎuČŕ`Ů[,Ó?i=99‰¶­-Vv‚uźvĂ*ébE7E+čX4–ˇ¨ ‡Ů÷Qúékô ZAŻŁ˝očzčégźV«Ô˸ғ$É‘á‘ˇŻ†ţ ý’Q€‚V$&Srŕ§yôol:FQTÂâšŔŢd»»ş{>ę)n±ĺMÎĎ<ś§ś]ďĄ~Ë Mˇ˛b·ýYúň%‰`(Řt¨)+•Jß%źçś']JĹ“ŠřLśźćÉŐ$˲ĺ9çyüHň~ęgÔłłłâŢßüć7c1íFmbkłŐÚlÍ»Š$”ë”ŔqŠ?¸IÍŔsźq˙äř¨o4›{!ÜNóŚ&]Q™Q*•ńą¸ă”CĽ'@wz˘ŃhëŰ­ő{ë9.íőábcŘn\ Z;¦ÝüČáĐlŇŔ•® ˙ř1 Ů¤)PX\ýŹĽqĸӨVů1ey“Űý–e÷7îďhëÇăÇ­ä%y BŻŁŰßiďţ »őŹ­ÁPźćŮ›¬ý¸}äüdúŘťp“\ôרűŚ˘Qió [ Pť]ťÁëA‹Ůdľ7Á”6’ŢŹL "ÝíĽ«HD_ŁgŞŰ6¸Ü-nđÄ`ăFö&»żaχ=úô V Ż|wĹrŔ"Y•DôÎ|˝‰ŰăKFf-Ót¨ y?ŽăX–eYÖŮ÷A.—«ŞUůŰ_ ‚ˇ ܇h4zä­# P”fm¶"§-—ËÍ̶÷m<Ďł7١/‡¬oX QůŔŐ€çëáb–ů¸ d˝^ÉuÚ•Qrb|iá8éĐŐčĐŚ0ŞŠ2í1ŤÇ4ŤüÁ¤tx0ĄÜ|Ŕ Ŕ0Śkإ٬QmTĄKé8é@Ë\§]PŁßŽ.ŹyŚjЍ$Đ8"*‰p8ĽÜJůY”Č‚ŢrZŻ”Ú\Ů8ŘđŤpí–‹ŚŢlî -m- .Y"* ´`'I7ŞŠB^Ëát¤+J„®c]A %!âvâzĄp8lÜaD1 sî›să×Ć5›4H˘Ů¬Y2w'ŮßšŹ6ŁeS Ż5í͇çWiÍŢť5ď3•„Bˇčéë)аXĘwë"*Kţ¬šEZŻ$C˝SĽ č»čźăzÎzŚ;ŤřU<ůs˘±čż}"|#¬|Ş„ça0’=ć^n-0Ź;b¤á9ëQ©˛şu …Ś;Ť(AßEźĺU **ôShë‹[ńšŕ⼌ĹbšÍšřLüHËŐFb0Ě2‚LżŻT|b±XSsÓż}b˝z}|:>ňŤô„ Á`0‚ďÇý úś>ł‚Á`0 &?đý Á`0Ą Žc0 Á”*8ŽÁ`0 SŞŕ8Á`0L©‚ă Á`0Ą Žc0 Á”*8ŽÁ`0 SŞŕ8Á`Ęťű%U,“ 8ŽYfd2™˙˛ąµŔ`0e‹ď’Oö˛TyÎ']±Ě“sSż·^.—“$©V©GΗĂ÷;ţÔ!“ÉW™“ů.ůd˛E´ńąx’däěö9-I’2™L.—kźÓú.úŁjĚ2â>ăn|˝QýŚÚw©.Ďół…¦i’$ő:}0T†Ż´N=d…X-K@«ŃfňÓĽĹl!W“4M÷~Ô[D‹RťŹ$#çG˘żFS·—É´`[I&(PX,ĺËďôş4äÇ´ĽŮ‰Dxž7í2íu˙bč´¤Üű ;UE žĚśPłI>^żŘ°,»ă•Ť§nO ÷„`0ŘőnEQKP5f)aYÖ´Óú)sË­JQăc8ćďňô:zżąôťC ‡¬0«ÇŻŤG"‘H$â˝ŕÍ l:ÔÄqÜÔí)ďoç{ťîŻÝű'kvw\ýéjęöň"9‚l+É ‹Ą|ąť^—A"pśtŰźD"! ®aUEĄŰ[*¸†]šMÇIQIĚÎΊrpťvŐn«… 0î0 ‚€‚´·˝ł]ˇP•EQź á¨TłYCUQеŠÁLÂńkăµ[jQvđúĽ‰*Ť~; S·§Rµ5ľdl>Ú,ţ«X«őŹ ‚ŔT3ýë§Ş(¤¤X ¸ ýö~¦šˇ(ĘqŇQ„†Ă đ^đ.ś®¤pśt@,·‹EşC–«Őę`S…S·§uóáćÚ-µIąjĆát0Ő Aýö~ď/EQEą†]ÂŁľ+©®ÁŐFA˘c ß×n«%* ŞŠjikî µ[j€ –7[·‹•tt’~˛č$ŽŰJ2AÂb)źHyś^SIŚ.FżÍć‡âôWŚRĢ^9Ć1áa×°K÷ĽîśçÜR7C±1ľdtśt÷Şę‘<0 sÎsnÔ? cߏ‰vüÚ8„o„AťťEÇÔÔ”"ŚĆ Â7Â’ÂŮŮY…BŃţN;ĘžÇ÷]Ť…&áp8qŹă¤Ş˘„{‚ Ţ ^Ő•¨­jŁj,06{w6]ĂT3ŁţŃöwÚ ‚š’’0ËBYĆ1 tĎë–[‹Ĺ"Ý!ËŐj0ď3wuw%óT!ňÔłw篲> ¨ä3h6kĆă]Çş‚00G"ół®F'dŚc†ń^đ˘*\§]Â=aćĂÍÂ=!‰0ŐL{g»ŕI·Ĺb%ť¤ź\ Ç‚m%™ @a±”G”Óé5•EŠcr~®ÄOóďutľŰI„şZťköw‹ ü°ěłŔ*h9Úb?aOÜk;f«{ąNŻÓ@,ĺrJĐűqođz$Iů“rđś÷ÄăqĄRéżěŹĎÄU ĎEʤĐ÷Oßääd{g;$)ˇÖ*đëďhëpí^˙űőʧ”˝éĺyL»Lń™¸ď|`?ao8Ř fęz·K«Ń’«Ą |`Ž^§·µĆăq˙wxf1f±pźq{.zś§śË­Č’’‡Ő^ź×|Ŕ‹ĹÔjµűŚ;ť0:qhSr*щt˝ŰĄV©ő:}<°Đ4­ŻŃK¦LÄvĚfŘn0l7čjtžó˙wţ‰‰‰ŽÎX4M7lübîĆűIúÉĹfÁ¶’LP °ú—Óéu)©Č5ąšt9ŔňŞĄÎTĽ^Âłůě'ě“““‰SîŮ›¬ň)%Ú¦×Ń’ąču´×ăµýŮöôłO«6¨>Đż ç&9čű¨ĄŃ×č´‚eŮTačfŞ˘¤#‘UĐřzcăëŤü4?|v¸őíÖK—/Ťś!W“¦]¦Á/5›5žóžű€C^µ€› ič*bŃbŽ= FÄyĘŮ÷׾€?nř”%¬¶··ľÝ ş]Ňl}C­ę^®#âČ[Gę÷ÔK ĺ”řiť>cÓ1ÉŮrdĺC—’áz& QaZAǢ1ö |NNN.X¤÷“ô“Yj•7 ¶•d‚…EÔżśNŻKIÎqŚq›q諡"Ş˛Ô܇ÁăÁqµj>ě5Ôě'ě˝Yx :ş‚‰FŁ­o·Öď­ç8N©TĆçâŽSŽDâţÚť*ül0‹Á}€UŤ.0íź\MZĚ–řLĽÉÚ„$ććÝ{wk6jŚŰŚ™/q¸[ś„đĘuĘmÄ`rĹyĘŮŃŐř> —/ĹĹ÷ !łŐÖf«µŮšąĺZej¸ 5›4pĺ‡+(Ä ü@’âÂÝá4Ďhgŕ8…2Ü$§P(Ě+éý@ĘO]í$l+É Ă’?˝.-9?Wň_öĂ}ŕ§ůˇŻ†t5şĹĐiiůÇQIA Ôď©übpÁ7;±,‹A.—«ŞUHh|ÉȬeš5ˇĐ„ă8–e%…†íç'?ÍKÎH÷_öŰŢ·ţŕ§yŕnqÎ3N±©ë¶ŐŃÖŢÖđzCj^ *‰ŔżÁëAË«–GvĚôýµO±VˇŻYô #Ěă˲ű÷w´uÄăqŽăVČŇÜĹ&o«yžG‰ą[śý»i‡)ťP.—›mďŰxžgo˛C_YßX 0Ę•`(xĺ»+–}Ťž©flŘŕ>p·¸ÁŤ€¨$˘wćMKÜFH::I?ąŘ¤k+kł=¤“LP °ú—Íéu‰É9Žijn"ź źX󸇖zů_9ţŮqËžGÎô¦]¦ŘťűÜFń3ü‘7ŽOäjrčĚű´H’ôů|±éŘšß­!W“z˝>řSPR¨T*űíýG¬GÖ˙~˝yź9µ|ŞŠ ýÚ˙ęţ'~ű„L&SkŐĘuĘ‘áďXć=fE•˘n[ť¤zíď´·µ·Ő™ęl¶%Ę·ľ¸•\Mú.ůFľUY7fŃP«Ôčúµî•:r5‰žB–.0M‡šÖ ~·fą5*>©‡,o«'''×˙~=ąšÔţ§VóśfŕótB@ó]žříú˙Ö·w¶×ďŞ/–Eő{ëµĎiwďÝí8éĐëô° |_čz|‚TkŐő»ęmÇlĐŢÖľ˙ŐýhöOâ6BŇŃIúÉâ"9‚$Űęř'ÇĹ×´H&(PX,ĺËćôşÄČ@ńŽźď˘Ď°Ý€¶=g=ĆťFńY)f…P÷rťFŁI S2#“ÉĽ>/şŠÁ`00ĎYÄHĂsÖŁReu—. wQ4‚$ľ‹>Ë«TTč§ĐÖ·âď”ěMÖóOăkŤË­)mp)pSbđqŢát(•ąMÔuśth6.Ę|4 Á`–‘ü×+a–ő3jő39żW yÎ/Á`0eľÁ`0 ¦TÁq Á`0RÇ1 Á`JÇ`0 )UpÁ`0 ¦TÁq Á`0RÇ1 Á`JÇ”8 }ŐÁ`02Ç1ŇČd2˙e6)?”ËĺyĽ›®p:ŢíýF¶ôőb0 łBČ3ޱ·Ëd˛ŕő`qµYzÜgÜúôäjR&“Éĺr˝N/~5>Ϧ„ÖöÖ޾ޱďÇ$÷vü©C&“®,gäüHô×höš­  E–‰3Xš„ď˘O&+(<9;˘}NK’óuiźÓú.J×µHř.jÂbĂóĽĹlˇiš$I˝N •üP*?‹Ň‘äý˘ŃhcC#2\«Ń¦V©đqŚď’Ż÷Ż˝A]›%Ćöľm·y·i—)Ž÷„@ `=jÍծ؝rť’$Ąľ¸vě'ěT5xbpÁrvw\ýéjNU+h­Čękä9YŞŮ¬ńúĽ9i’˲;^ŮŃx°qęö”pO]ďvQ•wy ŮT KÁwĂá0—§×ŃűÍű—[ˇ‚)?‹¤Hő~­o·j7i9Žăďňć}ćú˝őYŐt¨iâÖDä—HôvÔz¸8qL·”ěoYt¦CMÇMÝžň^đvľ×éţÚ]¸0?ĆŻŤG"‘H$â˝0ČZŢl‰D"<Ď›v™öżZž#h±!ňÇI‡¸=đé@$%3 3~mś˘¨ńkăBɉD çĂÉ˝ŕ:íŞÝV `ÜaDÂQ˙¨fł†Ş˘k‚ 0Ő ŃŐÝ•Zkإ٤qśt•Äěěl†Âk·Ô˘rZŢl!|#\»­–¨$¨*ŞĄ­E¸'ť+ňKäÜ7çAhďlW(D%AQÔŔ§9YÚ˙·~¦šAu!ŁĐ UőúĽIŰ’Ť#2úí(LÝž’¬.µ %uHgT–-\y†C9~mĽvK­j ÝĐ:ç9'©íŇŕ8é€ XFŠNůY„ô~Ć—Ś®aÚöúĽL5“MQhT†o„3U—ŇŰ]Ă.˘’@?¨‚ ’˛$^ÉaĹT3ýë§Ş(ďofżQBHö7IáÔí©DźÖ|¸ąvKmÂüt€ÔÓ«kŘEUQů•Ľ’IŚ.FżÍć‡âôWŚRĢÄ0‡8föî¬jŁ ť;K=ŽqśtdčIŔ0Ě9ĎąQ˙(Ś}?655EQjÁ±ŔTĚű đ^đJb|Éč8éî TŐ|Ćt… ‰Ă=aćĂÍÂ=!‰0ŐL{g{ş\‚ Ś_âěělj‘ŮRŻĎ‹˛ô|ŘCQ”]#©É<÷]ŤąËpř7ť® Su6*ë–IŠc’öÎÎÎ*ŠţżőĎ'¨Xć8¦á`îyÝ2*PtĘĎ"!˝÷ýv” †×t5ş,˝˘kŘĐóaĂ0Tĺp:’S¤éíČ/ŞŠj§=)SâŕMV‚ €jŁj,0††CżQBHö7I!jźŮ»óW•źPU 0?ťŔĽĎÜŐÝ•ä$Ă7®a—îyÝň:ĄEb‘âÜž+í6ďn8ĐP·ł.§\+“X,tUÚç2¶c¶ş—ëô:=Jě9ď‰ÇăJĄŇŮź‰+Şž‹ž ĺs·¸ŔŹË> ¬‚–Ł-öö …'îňçźččě€U@ÓtăÁĆÁ/3ä’Sr¨€ŢŹ{×$IĘź”çd©ˇÖ RÎOóJĄ2I“ dĐV˙[G[‡űk÷ú߯W>ĄěýK/Ďó® Su4*×–I§­ďźľÉÉɆײ4vQqźq{.zś§śË­HŃ(?‹éĽQI(ŠP(ÔÔŘD+h%ŁĚ¦´ŘŻ1’ Y–íý°·©±‰źćdčípę÷Ök6jlÇlŞH7´»ŢíŇj´ĘµĘĚ~ŁTěoé:at& äęůi”śŠĹb óSŰëóšc±Z­vź™8ĹOóďutľŰI„şzÖŽ”(9Ä1ÁëAĎ9OŰŰmhjR,{ú٧ ™č´Ľ Ü$—.˝î‘?JŮ÷Qúékô :Ó[ű űää¤ě?d2™¬ó˝Î+˙{…˝É¦+<ö 4=ź€VĐ“““rŃëhŻÇşzú٧Ő*uę2«Ě–~6¨}NŰt¨éóSźg0'µŇL»WAă덾KľŮ©YŰ1[ßÇ}»÷î†ômޤQą¶L:m'nM•„ô”¦ĄĹyĘŮýçî€? Tfuň[ů”źEtŢŹźć·ľ¸µ˙xż˙˛ßëóúđď6ďNĚh?n'W“äjҰÝ(G3lP0mŢcŽÇ㡟C‰ 2ôvk‹•ť`ݧݰ*“Î醶ĽJYřŤ’@˛żeč„rJbČ›ŽQU 0?Í µ†ş—ëz˙ŇŰŇÖrä­#HH®&ťCÎŕő MÓu¦r¸_°4TdźTýŚzvvVü÷7żůÍX`L»Q»Z-†ZŘ?±ŰţśéšFD©TĆçâŽS1ĎÄ}<18W«ÔbuööŢż,ö)×)€ă8ä¸InÁEI†íĂvC4m}»µ~o=Ç=˛d°4 6j ‡ĂJĄŇwÉç9—öw+mŔ—r5i1[â3ń&k¤iĂt:¤•GËH˘xRź‰óÓ<ąšdYćň(Ł8O9;ş:ßäňR˝N˘ü,Içýü?řcwbuŰęŔPkč˙¨?)ޱ6[­ÍsxU*Ägâ$I"7LT>2ď>]owźq˙äř¨o4ó”l†vfż±ň‘ěo™;ˇf“®üpyĹŔŹÍ&M­P®UŠŞq›q諡K~|Číą™Dć ‚• ˝Žn§˝űîÖ?¶CA~šgo˛öăöt«ÝŚ/™µLÓˇ¦h4 DZ,+™Fţ1BTbő{ężĚđÚ:˘’މ€ľFĎT3¶lp¸[Üŕ‰ÁĆŤ aYÖŮ÷A.—«ŞU9Y»n’‹ţE÷6‘u‰Zţ^Z^µdĐ!˙eżí}[ŕ_tŐÂÝâśgśş¤iCI$ŤĘµeŇaŘb€ čěę ^ZĚ +–úŢ Ë˛ű÷w´uÄăqŽăr]rż)?‹’ô~ŞjA¶Üžç‡żF]}A´ĎiUT]0ôŐĂ0‰îŇôvö&»żaχ=úô™Ë_ph/č7V8’ý-]'´6[Q#Čĺrółí}ĎóěMvčË!ëÖ…y(Ďó<ŇŤ»ĹŮ?±›v~šúj(ËŽ„™GČe˝’”ô<_„ă¤CWŁC÷x©*Ę´Ç4Rç·^𠂇Ť;Śh±Ă0hĆHÍó5î0&MÁCËкɻŽuf0…o„k·3šŐÔÓ×Sa®„ĂaŠ˘P! Ż5LMÍ»GŐF:"Ć—Ś‘_˛íH%Ä"Íó•ˇN/ŢQô]ô‰Ďq=g=ĆťFń-ć1ÁwŃ·Ő¸U¸/,·"‹Ď}ƢOüö‰đŤ°ň©˛šĎyDg˘ëՆһϜ=ÁëÁX,¦Ů¬‰ĎÄŹ´QmTá Sň<IÇ1‡Dg˘jµš¨$?[řÄĄK,kjnb'X‚ ĎFľÁď˙Ć”<ŹÉŕĹ`RÁq ć!rąĽäÖ,äţ}| Iä1ĽL*ř{× Á`JÇ`0 )UpÁ`0 ¦TÁq Á`0RÇ1 Á`JÇ`0 )UpÁ`0 ¦TÁqL‰“ţĂ“ Á”=8Ž‘F&“ů/űłI9řŮ \.W?Ł^8i±éx·CöŮŇ׋Ⱦ‰0Çăn|˝QýŚZôäIHDÉó?Í[Ěr5IÓtďG˝„ůč_¤r0ßýńk㉟Ě.]lďŰv›w›v™"ápOÖŁV‚ r*$v'¦\§$IRbß}°ź°SUÔŕ‰…żx˛Ă¸ăęOWsŞZA+hEV_#ďý¨wÇ+;t/č‚ pOD"ÎSNÍsšś:rB IDATŞ+"_D"ÂŁ@ް‰D"ĐóaŹä^pťvŐn«… 0î0"á¨TłYCUQеŠÁAj‚čęîJ-Ä5ěŇlŇ8N:Jbvv6Cáµ[jQ9-o¶‚ľ®ÝVKTTŐŇÖ"Ü“Îů%rî›s‚ ´w¶+ ˘’ (jŕÓ$5¦nOAEZKQÉ^ź7i›©fNSÍŃoď÷^đREQ”kŘ%¦PmTŃ|´ %5OŞËôLŞ *QbÚc2ýę‡(ˇßŢOQęi®a—j*µ¨˛ÁqҰÜZ“ňł( ×°‹Ş˘„n$|#ś!q–#%]źOu;ÂBCţq#µż€÷‚7s.ń R絩ŰS‰Ž±ůpsí–ZIa «ś’#1şýv4›ŠCĐ_1J‹zx3EČ1Ž1ď3wuw…Ă™†îĘÇqŇ‘!&†aÎyÎŤúG`ěű±©©)Š˘P ŽĆ bŢye0Ć—ŚŽ“áž@UÍgLW¸L܆i>ÜŚnś0ŐL{g{ş\‚ Ś_=éěěěÔí©dKť™,ŇÄ1 Ů¬Žwë"Â|Ŕ‰DĚĚş]˘Ţ ^Ô“\§]é4OŞëÜ7ç`Ô?*ÂÔí)˘’p »’âAtĎëŚ;Śłłł Ăę•% tĎë–[‹bR~‰„o„]Ă.Ýóşsžs‚ ¸†]č"aŞŠr8©Y˛)©}^Ňí,8ä7Rű[ć8&é Rç5t°fďÎ_|:@Q”¤0…‹UNɱHqLÎĎ•Ľ>Żů€9‹©Őj÷™ľ‹Ĺ€®Jű\ĆvĚV÷rť^§G‰=ç=ńx\©Tú/űă3qE•ÂsŃ“ˇ|îř1`ŮgUĐr´Ĺ~žˇđÄ]ţďüť° hšn<Ř(>…‘Ě%§äP˝÷ŻI’”?)O¶ôΖ¦ŁëÝ.µJ­×éăńř€}€¦i}Ť>Q[Ű1›a»Á°Ý «ŃyÎ{2hžzZWŁCĎÚż4í2É©dťŔůąÓ÷OßÖ·ęuzC­!WĺK÷·ç˘Çyʹ܊ŤňłH„źć;Ţëč|·“ uµbżĆ`H‚dY¶÷ĂަĆ&~šOÍĺHIíó’ngÁ!˙X‘kK= u^‹ÎD€\=?a€’S±XLR‡ÎĹ*¨Č5]u/×qä­#ő{ ť+ş\PÜ$GŻ“>Á'ÉąIú>ęC˙ękô :Ó[ű űää¤ě?ÎZeo˛Ę§”’…'ÂŢb€¦çĐ zrr2C.zíőxm¶=ýěÓŞ ŞĎô/čS-e˙Í*•j§éÉ;“0‚ d0¬|8éGrIU‹JƢ± š'ŃřZă‘˙{¤˙oýövç)g<.1 Rů”RłYsĺŻôú3(YŇ8O9űţÚđ2ô‡Ň˘ü,J„\M:‡ś`yŐRgŞ ^˘ét Ż5€yŹą©±)ôsHű\ň,GJjź—t; ůLJ<ú[ęA©óş¸â§yäúbÓ1Š˘$…y¨]¬r0ü×]+×*ÓťĄJÔqíźŘL‰P*•ńą¸ă”Ăýµý2­÷ą'Çăâý´Ú-µI·dŇV´N ǡąInÁEI†íß%ßÔÔ”î]ýŢd­Ą‰sŤ9Žs ąRËánqŮh(‘ń§ ŮknŢc†9h˛6‘$ş˝”ĘČŮ‘řL\łYÓýAw~Z­pś§ś]^ź·lNůĺgQ:ŚŰڎźC R© >ż*$*3-ȉĚ#E˛ĎKşť‡üă@NýÍÚlgA¤DÉóš\.70ŰŢ·ń<ĎŢd‡ľ˛ľa•ćˇ|±ĘÁ‹G!–®XĘŇ( )3rŽcxž·6[ĺrą\./OŤŹś©{ąNţ¤\&“‘$©T*ëwŐ±üř\<żŚ´‚V(٤”%@ŻŁ[ßjÍŻĆÉŰŇ,9;˘}NK’¤L&“ËĺÚç´ľ‹ľE­٨ú˝őrąś$IµJ=r~dń*Zxž·-4M“$©×éˇŕrkT|ÜgÜŤŻ7ŞźQű.Í÷˝B¬ŽFŁŤ Ť(ŻVŁË,ßEźLV2×?…®ĺýˇVŁ•Č8Í[Ěr5IÓtďG˝EćAö}©X5–19Ç1M‡š&nMD~‰DoG­‡K;Žéý¨wÇ+;t/č‚ pOD"ÎSNÍsšĺÖ @A+hE¶_w8‚ ĚŢťííîíűk_ś“`YvÇ+;6NÝžî Á`°ëÝ.Š˘–[Ż‚hył%‰đo˙ßú™j†¨$¨*j`p%×iWí¶Z¨ă#Ž_ŻÝRKTč,ëőyQQ§©f‚č·÷{/x)Š˘(Ę5ěBąRËŹü9÷Í9AÚ;Ű *pŕÓT=áA#ÂěÝY‹ ß×n«EŶ´µ÷ăKĆćŁÍb^ĹZŨ4]-ŁţQÍf UE)Ö*2[ ŞŤ*‚ Äň%ł'¶Ş¸  ©•Čč·Ł0u{JňH@ż˝ź©f(Šrśt¤V$©‰ä1•<|‹ŤkŘEUQKPŃ’á8é€ Xn- đ^čąZm|É(U4’¤Ž_×°‹¨$Đ*€ ¤,čĚŤ¶%{řĂqqÁ» o)[’N[‰LÝžJ×͇›k·Ô(,DóűRŃk\^Ł‹ŃoGłůˇ8ýٱ¨‡ˇŞuăvˇs?Ă0T%ž>K‡Ó‘ąÇ€jŁj,06{wÖëó˘“hχ=E‰ †9ç97ꀱďÇfgg Eű;í‚ ĚÎΊý4›5ăÁń®c]A#‘ů€YWŁCEI–/Âřµq1pśťť•<‘‹qLä—HĂk şçułłł‚ ÷†aš7Ł[ML5ÓŢŮî8é Ş(áž ‚÷‚WµA•®–©©)1, ŚAĹ|‚T«Eˇ÷‚ő*×iW†ěb«ŠŰýöţT­áž «Ń!'‡ŃŔT3ŁţŃöwÚ ‚ššJ¬(ňKDR“Ô6OwřŹđŤ°kŘĄ{^wÎsnQ+Zb6čž×-·‹EşsO®VŹ~;JDĂk şÝřµńGvKŤ_qgä—UEˇľšHb“ÎkˇqĆofßR*$¶<÷™»ş»R…đ }fď΢> (Ş@a!š/Ř—Š^ăň˛HqLnĎ•bżĆ`H‚dY¶÷ĂަĆ&~šĎ©„•CěN čŞLĎnşŢíŇj´äjŇPk?)ç§yĄR‹ĹĶc¶ş—ëô:=Äb1ß?}“““íťí@’dRQj•ZŻÓÇăńűMÓú˝XTşňĺ”* ÷ăŢŕő I’ň'ĺ’z¶¶´*źRŞźU_ą|Ą˙Ł~Tµ˙;˙ÄÄDGg¬š¦6~1hÚeŠĎÄ}˙ăű {ĂÁ†tµxÎ{âń¸R©ô_öÇgâŠ*…ç˘GŇjQhŘn0l7čjtžóž ŮĹV·4¤jő«Ŕ˙­żŁ­Ăýµ{ýď×+źRöţĄ—çö=Ű1›^§·µĆăq˙wţÄŠ|—}’š¤¶y†Ă·đÓ|Ç{ťďvˇ®V/vuK†űŚŰsŃă<ĺ\nE–”<¬&* …B …š›h­d”‰{%ÇďüľűPż·^łQc;fËP~:݂År­2߲ňIjyŻĎk>`ŽĹbjµÚ}&ůLt& Čů%§b±XÂEµhij,ur‹c‚€†×ŔĽÇŹÇC?‡EŻĹ=8`˙ÍŠš¦e«d‰łääUóc{đłAísÚ¦CMźźú<±zÝ#aPčfŞ˘$OdĺCˇŘ)E2”ďőxC×CO?ű´ZĄN·|¦·Ż—˝ÉFŁQÇŁ~o˝í}°·XdÔ|Q zrr’\Mšv™żŚFŁžóžĆŤéjá&9čű¨ýô5z­´:IH+čX4–!»ŘŞâ¶¤Vɬ‚Ć×}—|łSł¶c¶ľŹűvďÝý°vš†Qi,K,<ť&©mžáđ-äjŇ9ä ^Ň4]gŞ[šJç)g÷ź»ţ€R©\8uąÁjűq;ąš$W“†í†D9?Ío}qk˙ń~˙eż×çő˙ŕßmŢť@rü˘mk‹•ť`ݧݰ*“VéĽ Yú–NjËj u/×őţĄ·Ą­ĺČ[G’ŇË)9—ß±éEQ Ő˘%¨± ¨Č)µJĄ€řLś$I”•¨$C­%ŔPk€Á¶?Ď_Ópç>ăN<;"‚ˇ`Óˇ¦p8¬T*}—|žsžteĘ+ĺ±X h4šĄ&™ËG79˘ŃhëŰ­ő{ë9ŽËP”Vٵ¶vľ×Ůńn‡rť…\!7ɡPććÝ{wk6jŚŰŚâEXj-JĄ2>wśr¤F]™áîpšg4ąf—ÔJr5i1[â3ń&kSjŐ€ ‘ÔD˛Íó;|…cÜfújhÉŞ[<ś§ś]ďry©^ÜçAf«­ÍVkłÄz«?]ŤÝ‰Őm«C­ˇ˙Łţ¤8&Ýřuźq˙äř¨o4ó0ÉĆkĺä[V ™[^ąV)F~"šM¸ňĂä˙?4›4 բٱ<Čí~Śö9­jŞŁ«†ľbF­*Őűáô:şýťöîş[ßjeo˛pxžźü5ąßĂ'PÜ$ý5ŠnT¦;ɶ`śgśü4źý ” ĺł,ëżě‡ű —ËUŐŞ şěMÖsŃŁX«}Ťž©flŘŕ>p·¸ÁŤ n[Amím Ż7d¨Ĺř’‘YË4jBĘpDzlšŠ Ż|wĹrŔ’köT­ń_öŰŢ·ţ@×%Ü-ÎyĆ©«Ń=L1Đ÷×>ĹZ…ľFźWRÉ6Ďďđĺ js~šújč[J–e÷7îďhëÇăÇE]ş@pÉŰjUµŠ [Ź yžá݇“ú€äřeo˛űö÷|ŘŁAź®dÄ‚^+7߲ňlyžçŃw‹łb7í0ˇÄÖf+ją\n>`¶˝oăyž˝É}9d}ĂZ pQ-ZÔË !ëyľ‚ „o„5›5D%ˇŮ¤ Ś-ĂLˇ˘âp:tĎëćď*USÍŃ.Hći>`† `Ć5ěŇlÖ¨6Ş’ŔéZýö~Š˘ šG,ÎóEʬ&°÷‹Z%ËaüÚ¸f“-OĐlÖŚ~űČ*±ę‡T€f“Í˝Đz‡-Ö;ĽŮ‚&Ň ‚Đ|¸YˇP˙¦«%w‘śa´~JŇj Ş(¤ą8ű;«ě i“´Jd<8nŢgVmPˇ'›TŐp°Aś™LGĘ‹}2±pIM$Ű\ňđ-ŞŤ*¤’ń%cä—´óÍK×iWbOL]JS¨6¨Ż ‚¨$Âáp!V{/xѸŁ(Ę´Ç$él“ĆoK[ ęęâo~RB™˘‡É쵲ń-+É–‡ĂEˇ‰G Ż5 )˙‚ @óáů‘łwgÍűĚ(MO_OQ„y}_*VŤ+Ešç+Cť^ĽŁč»čźăzÎzŚ;ŤâZLŮP÷rÝ˙ßŢýÇ6q¦y,…ÓĚ*HžUzK Ů+8Ő.T8G%ěk%bJŐ:pÚ¨T*bşR7a«˝$­Ú„­zIZí^BŐ6骬ťJ%ˇŇĚ ÎfE›Pí]B$>••ŤĘĘŽÚ*¶ňX€4÷ÇcŹ˙Č/'ߏ˛ßŚßyŢńĽŻĎĽă1›ÍĘ µŇI3Rˇ§ź2•FŁńüě¸+Ŕj¸Řaß!ß“ç^`Ń)™†ďŚŹMS™S0´ď¶łl„•.śť¬ŞŕőŕŽçvŕľ«NřFŘ÷źëÚ\Úb•žÄ,DT«Č=ŠĹbă×ĆŤŹ—ßI"€R6ĎV))yĽžĺv9I)Qy>ó7aî¬j±;1“ÉÄUrý÷Ď˝4Ŕ ‚şţłk˙ÁýîCîÄt"1ťprď?¸ż”^§ĘĽĹěřó_^iţĐCŃ[Ń­ţ×´¬±Đ s¬E–ĺéé鎷;ş; Ţ΋Łéő¦H$"IRÝ‹uűî_ępJµ‡p8\·».x=H÷Ý'ű.{(’nKşőşýŽŢG•Ú Ş=¨áŐ†h4:ýĂ´˙Ľżí­¶ˇ/Óżż©.Pba˛˝űW'"‘H$ńź/u$\= <Ż´fö>8¦Í¦äýäčĺўޞ… l‰i4šˇSC¶ť6ÍMíîZV8ś´í´ń<Ďó|í µi/˝něű¸ĎúŚ5u-Ú*-EЦN´d˛?‘P%ŃÍ[7ąJ.3'č˙¸ż÷“^ăFc|ć‘^š¶MňÜ8ŮLMM‰ëÄÔxҢMŰžÁAm•6GĂxĽç>'­y¤0Ű”­Ą,ž97u)řµ<›fî<謭«]¸ ć‹i• iĽ'˝ÝtŹŹŽgvŢ˝Ío4‘e›%paîůĽŮ¨Ź, ÓŃo/Ę˝źô7•ďŞý}Awň•Ů­@DŇŚÄRŤřL\«Ő¦ľDu ç±ElJYí µÇýőŃ=űV×—˘s<ć诎ÚwŰMƲ˙©­Ň˛CL4Ą;z&q˝HDá›aŐż †äý¤ç¤gčË!ö/÷÷Ńjsµűűř»Ç‰Č°Ţ ¬ť˘SŃĚ‹’˘?ES#ŰN[ŕb`zzÚňŚeĎKé+˛ď´Sy?䫡÷”—*ČľÓţHŁ“w’ŇŚDDápÍ8› N6ĽÚ0ôĹwŔŰô릭xXOÎŤŁJ’$ď)/›'”Iu{ •B<g“‡b±X®Úפ¨VOKsoęyaÖüżŕBÔĽřVĚŕ?ďIok{«?ŕWÍňÝŤniF’f¤R’TiCAć_éÁBDíď´‡o†;~×ÁžŞöwZ”ť|A)=ČĽĹLD—˙wöjóńoÇY‰Bu ˘E†uĺŰ,Ě©ŕ÷•ąfeDZĎŃŃŮ1úŐ(ÝŁŘŹ±Ö–Vă&c¶C¶í6qťčjtEoEĄ)íçěĎŰőëô Ż6°Ď×h4g˙PżGáaß;aÝfŐoĐwĽŰA÷(z+Ú˙Iżë€+uńÉŕäĺo.;8ŮÓp8ĚbÁ¸ÁY˝đĐyĽł­Ą­˙Ó~6†öÜßÖŇÖyĽ3í ±m»Ť* )OxIDAT¨­˝mňÚ$;PÄWđ,·‹NEc?ĆرÍ9’†ą6NI’F/ŹÖÚką ®Ł­CuŐíiŰiŁűä=ĺ•f¤B/đQ­pΖι©KÁj–f¤Ď,Ű,ó[ů’XICžÂáđ~×ţÖc­Éd2Ť˛yô 'm(xÄ}"˘îşĹu˘uŰěA+ µ˝ŐĆ.îUíďŮvrwŁ{™źÚČěA‚ 88:Ţé$)|#<đ§6-Zi‹ę%ÎWs$IbűOôV´÷ĂŢş]ęßń@ť\Č<ßö·ŰŮÜĚ ‘H4ľÖČ~p•\ÝľşČ÷łíĄ”9¤ô`*ÖÄäDÍöŞ ŽăěĎŰĺGçâ…B!ű.;WÉq•ś^ŻţsúĚÍG6z™·Çţ66űÚďB5Űk¸JN[Ąmz˝Iľ;»Ľ¶JkŢj6n2¦Îť¸:aŢbf+2o5Ź\QmťÇë1o1SQ™·šS禶Îó™‡U5řĹ U«ÍqŔA¤×ëO˛T·Ijó37NŽćëőú¦×›”…JÍsnϞޭV+Š"›Ëś{žoŐ s·4ĎM]ă&#«ŮţĽ]ŮńĘÚJT7r•qÇUrˇPhđ‹ÁÔ›ă h~fm©M›ç«:(f×^É™·šÇĆÇ”B¶·o×ViŮ>–ŮßłíäDÔx¤±đŤ´xT{PâvÂń˛«äDQěěîd…©mQ] ÄÂb‚Ďx÷CˇV«e5תg“µWšç«a]E9©¸°íśýŐßź}·}ĺýUąPÎÂ.†{‹Ç~ţĎ?}2l,lš ,¨9‡ŤFăř řÁôwX J¦á;ă3ó: í»í,a% çA'«*x=¸ăąĹĚó…űIĚäµÉxöĽ´GžçMFÓŮse˙ ń’$9N62X-ÖÉŕ üÝءSC®Ă.Óf“Ň›JiőüÖ–CŕB@ŁŃĚKUËPď‰^ŤFŁüN±4#9N~-ŻÓéşŢďĘ\^u ‹ I’»Ń-‚ î_ą‹®¨<¦ůŤćę-ŐŃhTş-9^věyiĎB„µhţ40ôĺP/Üeßuĺú•yŹg^tĽÓ±×±·îĹşH("ß•ÇÇÇÝŻą9Ž[긲 ‡Ă»ţ}—ë×ôÓň]yrr˛ýÍv­V»Ôq-¬¦×›"‘$Iu/Öí?¸©Ă)Ů}˛ď˛‡B!鶤[ŻŰď(˙e‡Ău»ë‚×t˙AQ ­žßÚr0o5űţy©ją \ t}Đ•:¸5ĽÚŤF§öź÷·˝Ő–9Ľ«.Pba^m¸yëfäűHě‡űň’ɲyŔó™GyÜ÷Q_$‘eŢ>xz=öüú ząl‘}—][ĄťţaZ) }’e9ô]¨ćŮ®’ÓVi›Ž5ÉweY–őô=żďŃVÍ~ľr×ôz{Őŕ5ĎÖPŮwŮeY6n2ö}Ô'Ërâv‚*¨Ą­…ŐŻ­ŇNLN¨V®Z8qu˘f{ WɱuŔ/ËrK[‹(Ь­%U$!˘Î÷:U›¬4Áđ÷üľGżAĎÖŘ×ß§l´¶°Âľţ>ă&#ÇqŤŻ5˛Â‘ŃóVł¶J+®•—§Ö˙psUň*Y–ĹuâČčHjT#—FHyŇd‹“mŤÔÇ“5ĎÖpÇqśýy{Ž8—•ÁÓÚ*íRG1ź<źy¨‚–:Š…BDţóţĚňâZ]hm™ĹŕéA®’c˙¨‚8ŽK{‰˙ĽźŤór–Ţô°Űž÷ç^–•P(¤×ë'®NhµÚ‰«˛,O˙0ť:24i¬Ů^“úŐJ,,"r6JłĎšU%5»ą4’Ď?–‡°˙•,E©ŠíŰç1#—F8Ž«?Tß×ßgŮfa{O™"˘‰«ú úş}uJIč»|WÖëőŤGĺ»r$ŃoĐłD„Ś›Ścăc‰Ű‰´ĎQ˝^?ě!˘±żŤ5itpȲ<řĹ Çq–mY–ÇĆÇÄu˘zĺj…‰DBŖ߶ȲśHĚ®qâę„҉Dćgżç3eľqJ¨Jü?{yç{ťZ­6[[”B˙y?ŰiżśžžÖjµlŁŠŮŇ6{ÜÓŰŁ­Ň˛ĚĚŢo|ÜÖ]ٲÍÂÓP(˝og‹3-ŹI$â:±î—ulaVO¶8—‰ĐwˇÁÓ–§-þ᥎e>ŐżRoyÚ˛ÔQ,”l™Gq­.¬¶,Ců>˘­Ň˛#Uj“­7±®Ęz}ŽáeůHÜN7‡˙<,˲’ǰ–&n'Ř2}ő)mdT(±°ŕORuľ×©×ëµUZŹ×SD%ĺhň‚ďwÍUr˘(ÁO?ů´î—u˝ˇĐ–žă˝'˝˙fý·ˇSC{öÍž#ýfôćÍ›­m­´†t:ťëWďtQű›íŐćęĚz:Ţî¨}ˇ–=ŽÇăÖ§­Ío4Ńé3§[ÚZÚŢj“f$ß9źý»jĺöťöĚBËS–©©©–¶"âyžU.hŞ ®˙ęrr›6›”rE<'"]•.[“•&ŘjlD$ÍH˝Jµ-Jˇm§Ť,Ű,ľsľä˝d2™4 lţŻX%ú.řÜÝi›=6n0675ţ°í´ő~Ň[˙J}zLkhôŇh˙ű˝ź{Ź6ŐëőîCn÷knÖşlq¦ ü50őŹ©®K]Âc "ňťóe‹sÉI3Rë[­W®]EŃ´Á´ÔáĚ›ˇSCľ ľŃK«kbřü¶:[m9†&şG{^ÚcŢdîx»#GÍŮzëŞŃ[ŃÜĂËň±×±·ţ@}íîÚÔÂŘťńkgĂÖ Ú´Cu ‹>ţcśîĎńáp¸˙ÓţWCÝî:ĄÚŐ đu đuľ3 í»íą(,Ź‘f¤ĎíđśôÔľP¸ptîuě={¦Ľ§(Z-Ö¦cM ‡¬O[YIřVtşŮT@'ꦦ¦ŘcˇJP­D·ţ‘ĽÁVc›úÇT8öťóőüľ§˙ŹýŻ wŁ[µrŐÂૠ¶J›6”čÖëü>Çď:žxň ăăĆľŹű¬ĎXS`g ˘SŃ´Jú?îďý¤×¸Ńźy¤+ŞľP)Ô‰şx,ťŠQ÷űݬкÍ*ęÄĚMÄókůşëú˙ÔoŢjöťóőőö©„µ†\‡]®Ă.iF:}ćtóÍżşČv­lq¦™ş5ED†uŹ$Ö9â\rüZŢ;ŕ%"çAgm]­2Q±¬yOz»?č϶ű­H9ZÝ{˘—}Ą±lłä9u=Gm9†&w“;|3<ÁŮvÚ>ýă§ć-fAT+W-´í´Ń}ňžňJ3’r=K8ýj”î‘ Ć ĆĚőęÖëZ~ŰrüÝăÍżiž NJ3RřF¸÷DoÚ•˝ńźâDťŠĆ~Ś ť"z$UĘf28yů›ËÎNűóvý:}Ă« ěUŃh4Îu˝zíłµÇk9V8ă¤ŃčWŁďtŚ˙ϸ4#QôVÔ{ĘËv­lqr•Üř˙ŚO^›T˛uŰv›¸Nt5ş˘·˘ŇŚÄN$çbbďŁ4# |>°úQ8ŢďÚßz¬5™LFŁŃÔ_%XÁć·ŐsÖ¦:P„o„÷×ďď|ŻsÎc'söú9‡—ĺOAD\GkHÇGÇ;’$…o„ţ4Ŕ.iv7şY{U(±°ŕ«źŞ6>nlmo%˘Ďôz˝É¸rÎ,/ ąyľţó~ó3›Í^·Ż.Ű|Ҳ@ŹÎg3Q^Ż´ýÁEŻĎ^=D)sKŰßnç8ŽM8˘´9§çý˛,÷ő÷)µ±IŻío·łeT+W-ěéíŃjµ˘(zĽz0Ď—m®’3o5Ź\zäÂ…ç3Źe›…˝ÔViëöŐMLN¤…ę8ŕ  Ňëő§Í[ÍĆMĆlma•°e”)iˇPČľËÎ"ŃëőlÂ]úË'06iE‘µ+ÍÄä„ăe‡ńqŁpý+őĘCŐ8ŰŹ·Sé7čŮĚć×+mŻa—l(×+©Ćą7YTöçí‘ď˸1_ ¦Ž*™WͬĆÇŤě{3Çq\% …JiuqµeMÇšHąd‰«ä‰DęKRçůćîőy/Ë )Wś$n'/;Ř<ÎÎîNeĆ#Ť9(±°ˇďBć­f®’3o1ŹŤŹ]OyQ˛ vLd.căcŽŽ9çůjŘţ­Ţ \°éśDä;ăłď¶+çbaŐRΗ˘ö…ZłŮśűlĚ»Ŕ…ŔűůžĽÔŔj§dÍo4{Oz•§;žŰˇ\Aťú8:íţ »ë˝.–Ť°ÂŔ…€ó “˝6x=¸ăą_Ż«PéILřFŘ÷_ωžy‰ňrŹbwbă×ĆŤŹ/ë“D°šíxn‡ňżRňđ‡aň€<””<^»GěNĚd2q•\˙ÇýK €:˙yjĂJ Şy ,Óf“i3&˛,*A–çG©RS™B“Âý®`i±ôĄ$†ÇŔ’+.‰!ä1PľÇ@ąÂ<_XlyŢv`NČc`QĺsČ<ÍťÇŕ˛=/]ďuÍcmĺ y ”«ąĎ+5żŃĽqŔrc{Ú¶Ô!Ŕ˛ř:˙Âó{:I‘×<_ďIo>‹9:ó\–9çA§ŃLB.Żůg Cľ×+Í9ŰWą€ ó‚ĘÝ|] «AţÂBŔü(WĹç1i7ÚXń|g|ů?X…?7(2Źa"•ŐĂwĆç:ěJ}jßmĎöW€UhIrbň%ĢďN P^Xš˘śfIŚN§Sý+Ŕę¤d‹™ĘśÇŕ ¬6™IŚë°K§Ó±$1™-[(8ŹÁ1XUT“h4Š$ ‡EËŠ9Ż´$Ž_¶$Fő)Ŕ*·$ÓNŠśçËBıXŮě»í©iJî§«Ü’äĹ_wŤ$R-~n€ßÁ€r•÷} ňţQaüš5Ŕę±´źűyĺ1ůßŢián‹, .u°Ü-ůçţÜyĚÝhĘZęĎš/•9ňÜ2–­\yĚrČł˛ÁőJP®Ç@ąR9Ż„91ĺ.ő„ ŢMX18ŽK+Qźc4>X™×Ibž¬ŞßĚq^ Ęň(WDäúőŮđŤ›J‘swúÉ'€%×*řv6ią8|”XcÜ 7l ßą+K@.JĆB»z.ťťçü{lÉ"( ćÇ@ąBĺ y ”+ä1P®Ç@ąBĺ y ”+ä1P®Ç@ąBĺ y ”+ä1P®*TKÁŕ"Ç ÇwĆ·Ô!,ô<ưQď=sł *\ű´ó̇Ŕ…€ňă¸%Ś ‡Ŕ·ÚđŤ›ů/oÁü{,µ¤B–eŤFÓŮ;˘üÁ°QoÜ äYcđď1çÁÚü#`˘wFóO9HÉUÂ7n^>ŞŻłśWz4ŮÉ!|ăf4Í?Eţ)G&ľ’« "vH¦fW6ęç+2€ůĹÎC]>ęŘ^ťŠ><sqř(Ń®žBk ^Ǥ`(XđďRAócčAşŇţJK<K&“Y–‰HŁyř`â퇚¸$%鎋Ĺ˙“pd…,IEND®B`‚mdbtools-0.7.1/src/gmdb2/help/C/figures/gmdb2_window.png000066400000000000000000000557721222645741400230210ustar00rootroot00000000000000‰PNG  IHDR<`0É4ÜbKGD˙˙˙ ˝§“ pHYs  ŇÝ~ütIMEÓ dwA IDATxśě˝lUşřýä+su,eĄńĘH3‘Ye˘‚pˇ+ěR„ťg‹n]X˝MZ$’Ŕ RXmvĹ&-iwĹ&aĹ6-$ …¦čB$Ú„«-5W[ę ˛ő [jŁmÉT—c]¬ÎčK„GďF룗‘úţqĆă‰ă$NęÄÎp>Ş*çxĹL B÷^¬xą^pLśśŽă»ô$™LĘs2B¨ĺÁxÂüBHp Ţ^®–€©ÓS„ëŮ8ŽóűüĽ›_t Ë(â61ŕ ©Ň’ę-E’$śĆ>źĎ»ÍKK!S§§€čK?Á`l6s4[íZT­őą'T´ÄŠ–˙Á̢,Wľš¦BB€ÓEfrˇ{BY=›Â)śĆXĹá¦0Çq€(Ňc”oůŠ—âTŰ-=ůŐ"hjZĎ|HEśĆcSiá4PŤµľs2 cMZfŠ(­‚S¨ľABUëEMÓNĂó<Qş áN^J6ÝÓD+EżŢÍËWäĺ®bf2őţҶŻpIPÓ´x2®Ík!ßźX/Zżĺy!¤iš¶ Ń ĆXäĹĄç\zůŠśĽ” ďsGglćg„Ďç+zéčŮ(ĽUlÎG ăűFčžĐrúĄčěČPZY=kI’Ě?—ž.XŹ':%Ľ€S8őuJđřk,đBf>Sp°ůYEśÂ™ů Ń ťKŞŞJk•Â)ä@>źŻčUĚ śÓáäÜ\Ń*ťťÄ¦cŕ€Đ=!ůKYş ąÜ.:ĚWŘ#ŕ9ŚżÄŢ^˛@4Móz˝ĄśÇĹą@QT‹”y%˙YU|»|ŃŠ^š,˘¬cÁ#mÁ`lÖĽ,˘ĺ’$•r­ĄcýmqďÁĺj°ňWV¨ĄJ™W@%­Ô ő+ MCt›‰Ĺfb’$)ŞâÝáxˇčĄń ńÎŻ¤˘Á#pÇ <(ŞRpŚx“9-żĆČ–^´čy¨˛TżQ !t9TͨڂFt"¸…•/j y˝ŢjÎ`0 +Ë..§úJ?5ŻĚ+rJÖ4’—’ËI=/Ě©r đaZ._’“ɤ–Ń|>ßҶě+bč*rţ,<‡ń¶–Xá8Ő"˛@´y §±ŕ)˘&—;çć2óEU·2󙌚á8+^Ú±ęę,Á`l8ŞŞb\Ü\ĹĄV˛łT×Đ¢gĄQł@o­Ic€Ŕ IHĘ—dVť©Ľ–ę „w‡§1uí[Ó՝lj@Ü&úv¬tŃ#ĘWäD2Ač—°ÜyNçeڱŔ 褤ü5ÜBé—f0ŚJ±śĆ˘_m´Ň*Ş±ĚŻ–ęťâ.ď&]†Ţ Ëz.-×9WËi /đůc,+Ş:¤ľN)Ş‚ňŢěĄß JZ˘UQN–ąĘęUŇAäEÉx#â\!¤čęźx“(_‘µ !Äq\áÉ—?w#s išßë§Ą&±Ő/ÍÜč Ććłdp[ĂÁEXa(.ĺç9¨ŠZ¤Ć–ü|őő©µN°¬ř}ţŚ–1Ýđ  5C‰ő˘×ëÍ»ę ]ČUÚś›ó{ýë®=IčžPňRRž“A„PQKBssÚĽ–ŹÍ*í<g(!«3QXÚĄ ŁR˘¸Âň`)gXa¶´*ć’ž©k––X1˛çÎ&×™ôVŐTę#Î`0ŚęG[ĐxnĂÍTś’÷·ě7fZ×ăuÍ<¶ c ±Ąm–0—Á`0[¦´ ±epŔŕ+] Á`0VÇpÄP#MCěl,´{+íÄĚ`0 »;k´ťj(ů˛Ü|3[d0 Ć–)-Á`lŇb0 Ć–)-Á`lŇb0 Ć–ˇ|J‹ĺ~…J ÝawĘŁ´âźĆë~TW–S­‰şşşř§+m˙¸™TJŐpuÁŘJUZuKw<ţiĽ®nCĘĄ—k5/w°µ±ł±Ě|¦,W¬««üc%Ă®ëęę¦Ţź*(‰žŽVŞ> QqÖ°uîČčHÁNÁdśš:Uî*-{ąĺđßî7«ŃńóŽSS§‚îŕZ/wőęUúˇ®®®ôK3 c3ą®ĺÁÄĺÄţ–ý……ź'ö†÷n˙ńvżß?ţîřőśż(ňąµĄµá–††[ ŞŃúP+t´uţýá2^§pëC­ ·4l˙ńöÁAj:*Zh9ńűý´’!„•…\WW7ţÎx0l¸ĄaęäTŃ30 ĆVd 3­R d˙Cű‡‡†[´Č—ĺćps0ëKÚF¬¤óŇŢÖŢr erjt(°âLľ7YWWwbâDđî5Ď´–E‡ö¶öPShrbR™WZ[ZťČŮótĎŇÂŔ=Ć~eň9ňrä|üĽX/B˛ ٲU–rÁ1ŁŻŹŽĽ2=íîénÚÝäâ\ĺ­Á`T„5Ě´ş»şMcťÓ,%z6Jáoâź%˛$Ë»ůřĚ:%¬—«««“ŻČ›Ž©ŞÚűt/@ŮnqâźĹS©T×S]ŕÚnwĽhˇůŽăŔcoŽÉWd„Ë˝~…Q ZXŠ{űzýwú»žč’Éäş+Ŕ`0UĹuŮ´–’™Ď :ţĆqú§˙˙ş‡ě˘—SŇ Çqˇőťs¨Š /Đ?^PçŐ˘…ćO^85q*ňR¤9Ô\ż­~äĄ˙ťţő]˝@To•"d^ŕ€N°4M[ßŐ ŁÚ(ólEđD'#ŻŚ Ú Ń+¨i č ›±ů&ýUˇ*JQŢÍ-´ţ*ř“`đ'ÁŚ–ęxĽcöłe¬RQ!uýW樿©ľŚWg0Ś RćŚáÝažç{źéÍhČĚg”´RĆóAĐaęôY ť‡:—€Ňľ)çÄ"xg°ľľ~ôŐQĐAQ•±wĆZ´-4˘¤•Äg ĐÁĹąÄm"r”Y—$d`ě­1ŢĂűďXç<ŹÁ`0ŞŤr§qrŔ™©3„ťwílhhŘűł˝˛,ŻďLćśşşşĚ|F¬Źľx´÷ŮŢŕ˝ÁÖ}Eěj]Ouu˙ş»ś.sź—ż”¶74ßßŢ>Üw¸xamAë{®Ża{CĂ- ŃÓŃco+[erUZUČűÚßpK4#Ťż=ľ9Ć?ÁŘŘ&6¤®®îÔÔ©rşP2 F%Xş dI/á+¤˝0crËČĘY66âŠ+_t®¸2Á`T9%)­M"+2"W›¸žúŚŚŽx·yËXÁ¨ąĂ†°T Ă®°ý´ ±e`J‹Á`0[†"Ëxo~= ÁX•"JËw§oóëÁ`0 FN˘Š(­USŐqW¶1 Q2ëńd X Q#Á`0¶ Li1 cËŔ”Á`0¶ Li1 cËP’ŇŠžŽnt= ÁX•Ő•Vôt´óÉ"Ű-2ĘNáč騹mXěl,ţ÷8!ľ/sěl¬·§·ůţfóŇĺ܇ŚÁ`06€U\Ţ©Ć2wŰŞ8+oر˙ű˘ŕĘ^™rŃl¤.&.îôďěřy;ş'„jËĽë1%ńybęäTËľ–‘ѤĹ4U" ňäű‰î_wGOOüiXp ,—2Á¨BVšiU›Ć˘\[ W˙÷ęůOÎďĽkgőć¦Ň®ţďŐ‘ŃŁ±ŁG#Ď÷€˘*-Cż-/‰ĎC/ G†ýŰTPG ‘Ç!Ä…ď #OqľĄŃW#„Ť¸4Á`\'+˝N—®±p węVTE[ĐČB~]ëÜßÎyoőVćťý;ŁbÁ»§Ţ;ŐxoăůO΋ŰÄJTe%ę~TŁŻG”yËŘëőşÜ.8Ň$ş«ě“­Č+‘3S“řÓˇťá-éykyŔ'zĂŢů(ϡ؇ÉĚBĆĺp!džĚó cݬ4Ó25Ö*Ž:|ňŕŔźz‰s_ýĎĹ«Wż ˙^ěé}®›čĺ·ÍdłŮYy6óM&óMfif*Cceő¬2Żôö÷NťžjşŻ©ńŢƲפ,|őŐWb˝¨}Ł%ŻČNÎ%Ö‹-˙O2Z&K˛eąDl:ĽoⲠ:™ţh:vş·ă™čążť;;wţ“süťýňą˝Ľ@[Ȱ™Á¨NĘŕ›‰e´Ś˙vŻ˘ÉĆżyY™—};DB˛q)^ľÚ8ťÎíŢí®]®]˘¸xňôŔwŐłY= Á;ÇißhÉËɲWŁ\444ŕöíň  655ážúĎ(,!zy”Çč›Ç_9Ń÷Ěáčtü‹Ů/öwN{m„«EĽ›çÜ|xOxěĂ =’č(»@/šez‹Á`T«(­RĚZ±Źcϲ@Ś:€Ď{w±Ź˘ńÚŽ1VľVĚ ( Ćxvn6q9Ač Ş*ǡ®_vť81üâđşŻŐúPkl:VPŘţh{äĺČuµľřÇŔqś’VđÜěÔ»Çĺ9ěqt*ËÝřɨpł—ă\ÜÍľČËŁjZ˝¸j9Äq;ďşí¶í·Ý¶ý6é3•ŚJkŤ÷66Ür›o1Śjc%sS‰Ž’ëyşSž“łD3Ć8r"ßí^I’[jÍh™Ô\Şŕ‡Çţr,ü`x}ő^4Áúŕ;Üť]PďÂqŃŤ?Z˙č ;Ú;¬&1ęÄHéyşgݧĄ8kťĐ÷ěhş/0ý±DËĹzŐ˘Ű~|ýó‹Ů/śČąľVL}íü͸Ür8»ź;<ň§AŃĂ#äâÝ\"1 ócćÁG>â’sÜÔÂ,[ ŁÚXi¦U˘#F–€ˇĚ‚F˛Z&«-dÉB&3źQÔŚxłŘöp¸˙ąÎ‘WĎýíԹةóź|pţż?¸8w.vęŕ/®;é̇gjjjjjj2™Ś2ŻÔü[MÍżŐŚľ>ŞŞ*žĂ8…UUSŇ NaEU®Ó®Öň` &1Óí^ú»t=§Ą „ľřÇD?ޱúŹô†ţ8”ú2¸úżWÁŃŁŰ·oohhH|žX“ĐFßEŻů§“ăř›ťżęĹiŤč$K4ßw~ů—«…”ĘM] Ă/ °G2 Ćő°ŇLËę±Â”HUUPżVBt<ĄďćD'!äDDĎ’…¬ö=ÜX<ĚhdI9Đ:Ü ?píÚµššů˛Lw­üöŰořĂúwřŤM,uŕ€3.p=Ë\â6ńč‹Gűží«««;úâQłÜúůzpq.8˙Éye^!Yr°óŕŐŻ®&>Oěhřľ¦čŮ©đ}MGúŹ é?ţÎÄţ–ýç?9ďr»J™u)ó™ŘŚD§Y&NŽĽîßôŽĽ4,z„gţóńťoM_ćĆf`řĄc¨Ö…j96Íb0UĹęębŐEBj@ĘĚgŁŻNhókŘmkoxŻËíj{¸-Ľ'LÇî’ř.˙±Ŕ'0‘Śsn!DA[Ăi—§ý‘öľgű€ţ'ĆO„šB×f¸Ü.g­“ă8:)L|'Y22jŘáÂ{Bá}ጪŠžÎQ-*EiMťśňůKË]n˛ÄÔ[§¦Î5‡üçb‰é+ccÓ„j,Žă\µ.bĚ`0ŞŠňdÄČBbÓÉŮDŐ®>­! g‰ ´÷gű»üëĐ.ß~ű­ůYľ,€łÖ%z˘ĐÝ•uČO¶®:٢ź7"ä !„ŽŤŰßÖA5VěŁr€÷vQUŤdŁO÷<Ýc¸꫿rŚľ>:zţ“óD'«®Ý{cd˙ý·űŰKżJLO©W’G#G‰NśŕtŐ:OĽwŽh ŽsŐ:™Ćb0UHy2b@JĆł˙¸HLÂ05!Yää¬čťČYâ…čÂ˙ůóŐ[ń™x㽍=}=]Á#¸8čÄĹąňÖ,=KgwëĎáŽöú™÷đňďm<úâŃöGÚ×Ú–/Éqţyâ?NĐ»qőŻ&.ÇUE%:PŹnA ďiQRŇ"¸&ŢŹ*ŞbĚĚV$xgđÄř‰ŽĹzkv&šş,úĺˇŕo{Ä›Eä@±łŃ©ÓŃÄç 5­@Ó}MĂ/ ‘é-Qm”Á˙LćÝ‚ßÚFF”y%™423Ń™–|Eo5ă˝UTç zW­“ăřuŻ ¶?jhS«+Ô2ť2Öíőľ\žÜˇ?ŃČ-ůrR¨“’””$Ťd€č$|_SäŐČ©÷N nˇôU„Đö[·1űYĐUW4ŇŕµăÇĎ˙{ŔéÜ&rMa8=Ić8·^<4ŻE§cm·1ĄĹ`0އň8b„ś™břBŢ+ÝěŐsźuc¦jZ‰ťŤtˇµ:Şůr˛Ł˝:bČ—ĺóźśoĽ·€ď9ây>wQ’ó\ŹŢ{F^)(o¤ýz¬Y”Żľú*v6*ËrňŠěižÜ©˙Śťě ď ü'§Â÷5y}^9)G?ž˙´i6·Á BkËđDŹ'Č 4Š.'íčEűČ‚šŃÎFłŞJS"Q„Ď’q)ŢöpŰu6“Á`0ĘHy1Â{Âx.ˇ* µT™ĺ9W,čtťĐLć@˛dÁ@`ŤÓ,˘Ăţ‡:L×A:Ó˘zËĺ¸9W-Ęę`řľTÝtˇˇˇˇ˙·=ľ]ľđž0S˝43Móäö˙¶?r42ő~´çéž±7Dz:‘>Kö<Őy5ĎZg­^(®ç!˙„ `PUæEŻ}4}Ý­d0ŚrRGŚţúA]]Ă:®í»Ó×ó«Çťkžfĺ]çřĂše4f !D˛„ß&Ý\™¬Ć\D_üă‹Ű~|Çq8…‰–‰˙=¦Ź?ö¸w›÷Ô{§€čdôőQéł$xo7 ‘ üÖW…‚čë…€@!ć5…úmő,a.Á¨*Ęŕ!x„s±s ŻÍë¦Íąö­•Ľ:ôËCNä4®gć3 “Ąęj#¶őş–Í“»Msů“Îr^Q˛@P-xα֝9w)źpŁZ$zD˘i Đíđfd,/Ö'ZËrÁ(epÄÜ‚«Ö•ϰ^2¦;ŔZ!:űËHMM €ĂXüáxč—‡śµNńfďŇŮŞ˛#ęmÓřđTcŤüyŐ"ţFžss‚[ h#4M†ˇ«Ö%®čz¬ł·˙đať(vxAČŚŚŹ_NNëpxwU® Q%”ĂèˇÍ2Í^šĹ)™ż©ţŘ_Fä+ł¨ÖC®Z˙,éâśń™EŰN˘Ńઢ O.r"Á-pç4łQ89JĘ1¸nB»Ă=sr﫣=—“ę9 € IŐaŕ©Câ¶í,a.Á¨*Ę–cÓ0·Z+Ϭ~Đf˛8O.r gmůçR«Öˇő‰.SSäO‘ˇśŰ…ďNßąß xďđob= Ł$JrĨ®^˝Zé*”™R˛1mtĽ·űŹ˝=^Á:0 F‰¬´ $Á`0USZ ÁŘ2YÄą´ Á`TE”Ö蛣›_ŹëgřĹáJWÁ`0ĺăÂITqGŚń-e–O$‘—#˝ĎöVş" cSaŻŞßC–ő¬B×Á•ŮZŠ–BŐíV¬9lńĘ/‡me›†,m`ĄkÁ¨U–(â:H$•®Â:Ůş5‡-^ůĺ°MŁlÓĂ„y2 cË`ź™–m]}ŃŁk›|0śp„6ˇ>ë¦÷Icçá7NT¶& Ă60ĄUŤ  .÷UFË“˝Á=a9MŐ«´Žę?>€.%%ßćß +]©ő3ô;ĂÍÇ·CÔ4ŇöDĎÄ›‘¶'z*[+ă{ČęJË˙ňJË≧˚ˇN/·%„Âq\umLR˘(Ňcós"™ '{†aćHuîf…C.¨Ĺ;ĹogĎáąÄλv‚ľĹT×ě߭"N+á{üľŢŘL"ŘŽ(vr,p»<;áŰ˝•vvŢąőߌŠŮ´ęęęâź.JÇ˙4^÷Łş˛śÜ…Ń´ä…¤˘e@şL&“[=aą"'ČÉŢŕľ0Ě ŚVé ­ŚZŢÉńÎE—7ä˙iç·˙8wńŻG‡žéŤ<·e‚˛„wůDŹŕőŠ.ŽxBČU‹Ţ%Ü$řvx§ŢŮ2AŤ;ý;{úzzúz¨ęÚäK'“ɢ_%/$7ż>Ś-ÍęJ+~^¬ !Ů…ě WDçµĚ¨ČI\J¸8—uš—â CxϢ©Ixwřµ—_K\H„vqĚ# ä`×A:3“eąŁ˝Ă»Ă+Ö‹©Tj÷– IDATňýÉ‘Ńů˛<úú(}ě%IBůvřđ>ţćńS=%zDBČRőYsa»sŢáË~.))Śxůkőđ§d˛4Ť:KdI–wóń™8Çqŕ€±7Çä+2BČĺv•xuśÂÉKIż×ëó-Z˘ďňś›ł nÔůâK±™!Dŕ…d2IáÜśůŞŘőD—×ë ?&„H’“ďO¶îkT‹`ęÝ)<‡BÇ=y˘(Š˘敤źJ«ě:ü)¸ę‹/pyöi:řäAH^JŞiµë‰.pçćZöµLťž˛Vî?ůřŹ‹őâöŰ·BúźëçÜśo‡Źľ¬ŻňYBŔA˛$z6»ÉŤ,hd!ł‚aèü];;~Ţ~0L˙JŞË»ĂŰţH;č 'ĺ[J)˝QŔďEďß!†ďńůwx·{˝á¦`űľ°ßç úŚBEÍü°^¬÷ŢîĄ3É÷'C? ąjó=Ö·ËÇq!DäŤ'")%5UëůM­Ś`Ń‚´ţň—ňŇ–Ţި.&.Ěq/&.FŽFLŤµÜĎWhNQÉÇgâÚĽÖůX'@©ţŔEďőúşĂŢlĆLküÝń‰w&Äz1ł°čŮćoâéÁ-hg¸Ě|9Đń7ŽÓ?ýwř]n—Ŕ §&NE^Š4‡šë·ŐŹĽ4âżsuo{<‡‘ŔŇŻč ÍkV˝UT“|;ţޱ2é»Ýgéâ\€ ÝŠ~őîđJ—?w^ůËČŘ›cűÚ___řČáőąčrąůřé©Ř%yj.ËńüŘĂ˝/Zţ)KmZĘĽbmŽŕ4UłVŘřL @n@7YSĺÍhâ®ÇšŞRËN˘g3ÚJVłňŹvH’DÇ».pänb†dčŚnŐ–®µQ™’ѱúGĺ@¬ç­ÇČ)UN©Km‰-űZ"G#=ĎôL˝?5řü UaO˝?5urĘúDĐ;%,™±™ő/z+ݧkMĽ;A'[=}=‘ŁsUpâ݉˘Ç/ל˘SU•ă¸5mÉ]ô^_OvĄ$ĄE'U‘—#ćěŠ~.Eoá9Ü×Ówńż/ !ţi|úŁ".|-ăÍ™µ@đD'#ŻŚ  Áź? f´ĚĐŔPÇăł˙]őę$KÄޢ_Ap@ôèŐí"úaÜ´©¨ĆZ Ďó0řÂŕ OcxO¸÷ŮŢz±>pwŔ|1 ě v´môĄŃŢgKr1ŔĂžśI ÚÄ™˝/ô5ěvF'ަbVćŽ_ó»j‰•ď}˛#vaľË(źEÇŢš’?ÇÁű|Ľ 8€(CČmˇĄD üa`˙Cű'Ţ™h{¤mUkóšŮĚ5µ´ÄFu>Ő/_wďB€Sjl:ŢóŰĄ_…÷„#G#CBäóůĚ9"Nᡡţúŕ’’Ňß%ł 8ŤEŹXôBËÝĘut-JähÄş*HW‹® ®Üś˘Ci ĆKuqĹÄ|¦L–»×ën Ă®”´<y9Bőý`~.ĺ·ôELQ•Ě|†W :1žĂŇg’ŐŰ0Ľ;Ěó|ď3˝-™ůŚ’V”´’ř,:¸8—¸M,1čĘ»ŚĆŽăzžę‰Ľ™zŠBČÔűS‘W#ý}ýTŮ „ä+2žĂG~w„ţ$tOçůˇ? ŃRÓ´ĄĎ^ @˝öúktm¶ť©pµś9ą\‘çăÓńČ[SS´<ŃŐőD×ömŢŕ6|·†e}ßďáÇŢe^™:9ŐňŕÚĽ:×TůÄéáĚ\R´=ÖůXKüďÉ©wŁřK,c¬–Ľi€X/ö<Ýy5"Ëň ':€ńwÇyž÷íđ•ŇR„íQkj”śR:iÓąódHtZ?ky¬ř:9B(ôÓPôż˘­Z­ĺtQAýFŐ4-ú‘ńDžç#/DU!„,Ťj*ÚŔőu-°Ä›«‚tť°ŕŰRšS´b]ęŽK鵄ĺ-}¦LŠŢëu7ac6|¦Ľ;Řr ĺ–ę=ő‡ŹN&“{¶÷\ě|ň µŻŽüyħ?kě€3SgŽüî͡ŔóüŕóÂMBßs}8…Ŕ»Í{ěŤcĄÔ\–eQĐ2KámŹ´qnně­±ˇ!pčpč—‡ZÝăŹ=y5Ÿ䇇†;~ŢA+věŤc‘?EöŢż87×Ó×Sŕ¦íŦc{Ś5I˛@"G#8…Á˘G,q |9šĽ"éEÁw«tşJô¬é;^ymdčCŤÁF„PřÁp×]křůZ*?üĆ ĂÎ˙ףâ6żh?|GXů<Úű‡1hyp ™SÚn‹MÇ÷ź_NŕÝ]Ý!q›8üĘ0íĹ«¶ôńÇ?ňű#„Ż×[ú čśzg´íÁ«Y_•¦g’=mľ¦~ ‡ž<äŰá+pöńů|áüĹAžç{žî‘eąýńöÉ÷&G^začź=€Čw‡o䵑Eç*v+q —ŢĄÖ¬‚ÂĄ%Ą4§xs@˙oű‡ţ8D :›„˘Ď”ĺN"r|W˛ŢĺC$2ŇQđv!ŕCNťË:D´Ř\2”—D"86— ą]’Hl.Y᪗ /ÁHs|\®řĽÝÚÁeó3*"-řśL{‹Dě#qAF: şťź×€†csrČ-Ľ<8h źĂA·+ŕőI Ř6O±”*UZ:()E‚$µd()€–LçÖtŔŞŔi 3 ¤b—ő18m˝K8­ °¬))é§1H€UŚěł8ȰŠAşTUL§•Řb `U!`Č «é6‘Ŕif’tŮ“¶§±ŐYÔč˙:ŕ´0Ťmô0K©RĄEWYŲŠéźŇ‘¬b:BĺÓ8’V¨Ć˛Ď @‡'Ł]:"‚†Ŕl,‚HI)8Ťéa•®xy  1ŰevU%•ż×yÉädeţĐĐ~nHŔŇXkoĎwşxĆHGČaź§€Á( J• ^^ęE:Ł˘v QôŹAjë‚Gy‘S銗ŞŠr Ô˘Ł¤Ń#ŠĽh5Ĺc+iE¨7-:6Y1§o$´]`ß*m©` NĘŮ´DÚl%°H wŻE^ęs łmYĹf°ÍSŔ`,ĄZ•–ŕˇ^ |Ne$˘¤Ń#vň>u@`&©¤‘÷ř@2Vm}§ę…@ `ŚÎ()Eô€o‘/ĄD”tN2` q‘7űH0ŤUEôˇ]MŮś÷ S‡Ľd$b čy äî5ŕ4ęĹĐ®@6?ˇDH˛Š ĚŘŞ0T©Ň2| { śVŚőýĽM+gç‚ULG+ű, 9˘­–¦ŔbѡV®|6%Ą ÔÖ…Óö‘@ˇMËŇŇHÖdąľAmZJµvęµă¦€¶”>1óŮ5g«Ř>`¬…ńwÇŹüţčĎĹÎUş.H•öncí>·šO_9 »EJˇ:äě:fyµ¶f˝č ¤ł]Ô¤a,ZBŞ©°Ş`5Wn rjŰh/ý“Ú5 ,ťTVŰOĄë^蝥}€öâ Ô)É´_š8 o벋+Ę÷śşş:ó3ĎóÁ{‚=OőŰÄĺŽnŮ×˙4ľże˙Ő«W‹fý6v6ćóů\n×Ę?©*Şt„ŁOŁP/ĽhľMÓ% Ăž`®ň›¶.›YtíĄ>riŰiy,;™Q;GʰôP«Oĺj]Nč ěĺEˇ^€E÷Účy»¦!jÓ˛ËâUŔ9 ă)ČŮ/ŔśnćcřěeŐcŚŚŽ´ěk! döĘěĐ CÍ÷7ź‰žńŢę-z°¦iĽŔü·űOMťZîśÖo;~ŢqjęTĐ\ů'UE•*-ú¸Š1gÁB ItŔ2JĚü’Ĺž1¶y\éűň" –”¤V=jŃqęĄwO"8ŤE^ t…°ÂU/ /.]MFţ ő@Ä©ŁLSuř@˛O  ¤¦ś:Ä`Ú°ěą@fŔč÷Řę)`PP-ňßéźŢ|apüíńÄç‰#ĎÁiڍ§Ż§ýáö`0Źvô<ÝăŰĺ3§MuuuÇţrlěť1éS©éľ¦ń·Ç—ôŰÖ‡Z Ł­Łí‘¶đž°ůśÂ˝Ďô&?O"„Ú´ţíap9OĄ¤QĄJ rßfkK„ …óĂŇ#µoU˛Ňĺ#Ł“ł`-ŠR’ráŐĆŰ·iů°™M‹¶Śö"%…@IaiQŇw ‘Iy‹Ž]’ĺ–Ä© Ë.@ŢŇ™ XÄ*ٍĚuĐž „Zl9ţÎq˛@ö?´xh¸ĺ@‹|Yn7Áx<^WWwâíÁźăźĆ­?üăŕŕĐ`˙sý„/Ëfůä{“uuu'&Nď¶üD‡ö¶öPShrbR™WZ[ZťČŮÓ׳ô<ŢŰ‹Oř6šęUZTQ‹ŽŚâëúľą@dŤRŞâ­j§É[°ĚČ-jĺŇrăšŐÎa 8¬qZ¦•KUh¬žˇEËóP»H€.çíšÔ„i–äBEaËX=F.·‹,čŮ(!„ż‰O|–ŢÍÇgâbý˛¶®Ţ§{CM!ú9ŁeV~@âźĹS©T×S]ŕÚn{kŚ*­ÂóT*}ľésłiŘ®¨EYă´ÄzQôtĹżÂU/†Óż`Z°¨˝j‘ŔĄdJŔ.ú¦bµßĐ{mŘx,”()ç,=JĘpÓ°ů§Ŕc±iĺě—ÖÍ´Ś§Ł^´Y´"ŁEUxžĎĚgă8-ôßáwą]+üŠż‰/ýŞ˘€ŔĂŽŔ 꼺ŽólUŞ´rnB 0žL3N+ĐäÔ©öŚ”B-:0#ŮćqĄ/ŃFŚ €|”R`WӢͥňQJjů«tÝËť5ć% €DÝ&Ë©)jŐ#¶±ęŃYŁŃ·él{FĘYďÔžgDk1|B  q{•®;ŁüB˘FĂ{‚G :yeŐ–ßM”xPT…ę-EUxwUč*“*UZ梟’9Ł˘‹`FîA3~‹8ąšog_:dcŐjÓĘÇc-ĘĽgF)IDI)vJdeDŕqi`‰H“¬YQrĺj,Ű,ŽQ-ŤAš{ŔbéĚ­7Đ5sśV@’¨4*YoFŮŃ!ńybč…!čéëqŐşxžď}¦wŕ…çĘĚg!‚Ő©¸dBÚ7šµ$xg°ľľ~ôŐŃÁç•yeěť±–-ĺiE™¨VĄĺ –˛\îA3:ÇXÍ7m]vÉşfF)YóΙąeYÔóv3pÇZŞröŠ˘}ĂĐE}e†*šî‹’O2eąüO ĐÝŐÝÝŐ Ľ‡ď ;~ĚĹąŕĚÔ™#ż;˛ó®ť ĎóĎ®Oiu=ŐŐýëîa2ś_úsŔřÄxď3˝ ŰB-űZ÷._Ę@•*­Ĺ6-0ě†EG´ě Ô1®ňŰɢC,±^´ćť[ś}1?ÓÂiLóŃŃĎ•®{y0ÂęE3Ó`>"-×+¬QJfîAŰH€† [­´·SŰ•EFîAÚ[ědŐűžłB¨ŻŕŽ?¶ÜńÁ»ćgëI–ö<ÝÓótOAˇX/Nľ7ąBe*\ĄJ čăş(ď\Úš{0g…žšy/´«)Ó¶°€fŢóů,sfDšU:¦Cy  ™+]ńň°(RÍ’yĎFČő0ű€Íbőč”1wÇiś–UČ4îJÄąH5‰î×Ă`Ř”*UZą4Nůś\óžu#DÓÖe§°Ä ZI[ó1.ŤÓŞtĹŚ ¤J•ÖŘń±JWˇÂ0 0 ŚŻX¦Łjů?•®Á`0ĄRĄ3-Á°% s“ą>Ňb0ŚM˘ýŃöJWaËĂ”Á`lĂ/Wş v€Ů´ ±e`JËÂw•®Á`0V¤’J«¦¦&>_ý¸M!6«ů·šJע$ŞJnÁ–°eŁڞS6Ą5yrŇżË_sCMÍ 5ţ]ţÉ“…©«ŠBô5GÂÖXnÚmź•gW8ţ̇g2ß,»_Yl:VSSI]µir«j#Bď3˝ë;ŐZ%°r7Ř4Îś>ăßĺw:ť555.—ËżË;3ż-hTĹ;'Q…”Gi ˙i¸ăŃŽ®'şţőíżţőíżşžčęx´cřĄŤ˛:ž?qíÚµýż˙š|oRůZŮéß9{iY˝ő@řäĺärßúî𝋝Űj®Î&Ë­ ÷îÚµkß~űíŕó‘Ł‘3žŮ„ë®Ü 6Śń?{ ó±Îo˙ď·×ţżkłłłżŕ8nąă+Ű9Śę¤ J+óM¦Żżo`h óÉNçśÎ8;źěč{¶ŹľŰŠ7‹ŁŻŚşntŦcł—fCM!çś.W~«Í¸÷ďň»nt 7 f믊^×ůg0<=Ăó|ßs}EĎC7‡ŢŢŰű›^}eTĽYtţŔéşŃEH~žl5śůđď ‚@+9öĆFĺeŘpąťŤmNCÖ‡Ëĺj{¸ čv>ÖĆâ/qhwަŢgz©­±¨jjjĚîa~ž•gC»CN§ÓétîÝł–tJ‰…ćŁj;ĐćünAö>¸×żËo™Ď„v‡jn¨Ůűŕ^XÜ9kjjF_o].×řŰă+né^Á`¬J”VôlthxQüAűvĐ!öq Rs©Ń7GĎýíśďv_óýÍÁ@0űϬ™Ü>“Éě ďíyŞ'óMćĚ_ĎüĹAü%¶ţ*pg`…«;ťÎÖ­±ŹcEĎCG±3Ń3túâÝáMÄŮfűűú{{Š/LÍ^šŠ§•lŮ·Q m´ÜP-Úś†¬ŚńÁ®!ŞQňŤ˝Ăş?ä˝Ů›ý6;űŹŮÉ÷'ÎfłK%Pz¤«ÖuőŻfłŮ‘×FŔÚ 6íţ.%xw0pwŔôŹľ2Šq‘´¶˝Ďôöü¦çü'çŁDßż<<ţöx×/»ţâ`&“)Z¸Ő{±*ePZÚĽ‚{Ńdt«fUQéźżđűüńO㪪öé§ÓIżŠ~%„˘ꉓ»ůč٨őWÎ8W®ďćÉYá<&ˇ¦ëFWöźYQ5M+z6ç ż:<{iÖétşnt=ěúŮhą‰qs˛&:Ú;¨AkűŹ·kßhç?9/ÜdH€V[ľ,§R©ĂGÓąHçcťcoŤĹ>Š-•@QbÇÔ´:üŇ0mŻ(ŠlÚý- ˙$~¸ďđäű“ ·47‹ĂÎfłć÷ĎîÝł7ŔŇţ9řü`0ězŞ‹˙4^´p‹ö ŁtĘ\Ěą9PćAČŹż4U ý \nČ_Ęś›+tč‘‘—"ôĎŕÝA^ŕ­żZUUyżÂyLĆŢ}sÔ{łWűgqŤÂMÂąčąÁoűńmŢ[˝ÇŢ8Ľ'XJ5ÖĘFËmÓ˛&NŚźh?Đ7ůŠVŤŔ”‰Ŕ ŞŞ•@QÔŻU=…şĘ¤Âbą:źěě|˛3űĎěÔé©Ţg{§g¦Ďś>cÖm…źR™Đ·-Ł-ܢ˝‚Á(ť2(­đî08`üÝqj0 Śź„w‡­Gşj]š¦Áw7€ąľ!Š"Ńɉ·O¬:Ł*J6›?9޲ŻeŐóĚĘłq𫯾E16‹~P83 í…v‡2™Lďł˝­µ*ʆä ŰąmNCÖL1Ťe"Ţ$€˘ş\Qžç‹JŔŠňµŃ4şk8NańćeőV5Ĺůg{[;Y »®é‡ĘĽ9)--DN´U{Ĺ÷€Ţg×é+kĘ ¤ JËuŁëčĐŃ#ýG\ś«í@LĽ;q¤˙ČѡŁ‹ˇÝ!ĐaüäxË-ŹvĐÂđż‡ë=őqpdtÄĺr)ŠB×7V˝n6›M~ž<üÜaä@GQ-*zT‹2óČ-Ç)ŞÂŐrÔłĽčđ‡1VŇJđî ËĺňnóFaYÝvťl´Ü6­!ĺ%xw°~[ýŕG#ŁŠŞŚ˝9ÖůHgQ ŞE‰ ŢÍw˙Ş›–„î ńľóPçřńqŽă’ź'éLÂěK|&›Ž…÷„˝·zť?p*_+ă'ÇwŻd˛]„y9Â{řŕÝÁ˘…Y=kË^aL™ďĺ͸XžÜ˝Ďô !r4rđŔw‡ďÄŰ'Z´&ŠâČčHwWwoOďpdÎuśNg,ëţUwÝŹę€wó#ŻŚ¬¬´:Ú;:Ú; ľľľu_ëä{“t”/zžţľţŽG;H–´?ÚŢöH[㽍őžúá—†Ą R㽍#ŻŚś<»íţU·<'€÷Vďä{%N­Ź •Űf6¤śÜ±h¬óÉN睡ÎG:ź„`© ˙·ý}ý}ŁoŽŽż=Ţl§Óyîoçşu×5Ô! ݢ.őf7đů|• çćä+ňÄ»8… !śg'ôoIDAT›ky°Ąô7Đćű›Q-ňŢę=ó×3ćlµ ĐyM{…ŤřľMmËžŐľ®]»fĘ1v6ý(:ţöř ’ŤžŽ† [-1 cC©©©9;G=-W.d\'Š˘Đ!®ěgî}¶wĺˇŐ–(Şy9˛ŽĺAúĂđOĂ폶SˇÉ—ĺćű›YîAÁ`lŇb0¶'ţă„ďv_)… †˝aűi1[€˘¦l¶Ł ă{›i1 cËŔ”Á`0¶ Li1 Ć֦΂ßďďţu7ž+’ÜŇ$v6FĂ·"Li1 Ć–gdtäęŐ«_ýĎWÇŢ8¦|­4ßß,_‘—;¸ăç4Vo+”Á`ŘT‹üwúÇ'Ć977řÂ Ś˝9 niŘţăíăďŽ@ëC­ĐŃÖqř÷‡‹Pĺ0ĄĹ`0¶!Ôň`‹ô©^Ż÷LôĚW˙óU×/»ŽüţĐ4('&N >?Xô€*‡ąĽ3 †Ýpą]d@đ'A Dô´¤€U¨6Ňb0 »A·G€ńwÇ'Ţ™ëĹĚBqĎ‹U¨6Ňb0 [A‰~ ď ă9Ü×Ówńż/ !ţi|úŁé‚#W=  ©RĄ%üć 80§«@§U&:2ގ…ąŻ”?fIߊĎLÍ7› KBż…E‡é Ľ´·‚5/F íZů€Ľ|t‡­ű€Ůdzëu°Č!ß%”?١0ÖŚ‰ĎC/ @O_u TT!=˛@P-Bißhۉmé•lÂjT«#†ňO ĐéDŔAň…ćSJ ͱŰ6č{ŻĐ­˙ŁĹă×â1«JßCÖm‘ĂúŮü?×Cd‘4hg°aČ5ĘTչ۝żéą.ÁřžŃÝŐ]WWW÷Łş‡zwxĎýíś‹sď¶hy ĺ˝?ŰüIĐw‡oďĎö@×S]Ýżîž:9µÜŐLµŽp‹ŢhńĽŠ,žxˇÂăm@Á<ŇŻóúÉl2,:RŻtÍËE‘)…ĺŽ/šm=Ő6Ť‹Ş^üżŕ°ĽÁ˛˛‘Úf”ŔŐ«W—űjäĎ##6v ď1ö[éyş§ç鞨fŞv¦µxÄN™ =Ąć·¶ŃX–!آˇÁŇäütÓ¦B(>Ą°Ě9Ŕ¸/ŽŮižˇ±Ć_r°~ůŰmł»Ď`,C•ľ”Š €Qô8śJJÁi™–Đc.śĆXĹ"/ —’Ö”´M6Xó.` z*ŁĄi,zDˇŢ…tq¤#‚ÓyÉŕ4¶ŤD"ŽDŹ zŕ´–“€HwY$ŁPYŮIŢLDt‹‚G@€()EI+í‚tQR} ¨pZ¨öEc}T©Ňň™ qBŔ‡8§±›“s%ôťš‘ż‚· '-ŕŘ\˛Ňu/I@s|ť:H„ŘÁ9u”5RDp|Ý®€ID‹oŮě,x0â\rę\Ö‘Ť–z}Vç‰Ř\’)b $‰ÝBŔÇŃeiÇçä Űi>Y@}:Ě>peĄĽs Ć–¦J• aĂŚ±‚Ó k‰± „Ó qśĆ V1›¬ć#°ŠA2BqZ1d"ŢJ  JJ‘ ©¤űŘ´Ě> Ńż’RśV$«ç¤U2T­uŮ@€ś^ô€8­€$YE•”‚t„Ó Ě$±ŞTńcÍ`\/ŐŰ»‰(iĹXęŃ8%VŹ )iEI)ÄAlŁ´€Ş"śĆ•r śĆJjѨD€ @˛Š±Ş Ča ж(i§1Uá˝×´Ä¸Ý´o8Ŕ–}éČXđĚővăąH)†@KŔ”Le«Í`lUŞ´čÓ(ň‚P/ó %Ąő‚č¬AK8­P;‡č””"«6YˇŻP/‘6–^^ްčŽ*JJÁŞQn' č Ô "/Ň)…iŐ3K¨d”ĆiÚ7DC©Űă)0츹>`} rž´–r[Yől‰˘˛»s]T©Ň˘oÖB˝4Ka3I:`ľEŢb3I%Ą!°«I ŰĺqĄÓ‘·´W"t` šň~˙:H É*ęĹ@Ŕ'AŰĺ‘ ®˘G¦[ ’VD^ Üăłxx VăČŔi›¨íśÄŔ®8SG1%môöEţ´ˇĺˇ]n ŘŹöGŰ+]…-O•*-’›CH ŃĹ@¬bşTb¬ďö Ŕ*ŕ´0Mí[®ząĐ8aÓ:`•Zď$z@ŢÚ—“ ¶Ó4ËXS`F˘÷Ú°iĺ­zćLKŁ·LcU±ßň u]!gż¤†>Ă´IßTpZ‰ŮNvbřĹáJWÁT©Ň˘+ő˛Šéb—ń:Ŕ\ú +'ÔČa”ŰËžAŰB]śi3i‰ŮR0ŢvÓöcĚv€)E¶+¨i°Ş`5gď´ ÔÉ(oĹ4^ŕYµŘůrÂR{'a?޵ë@FDŹhd“K)˛Š˝Ľ(Ô‹ÖČb¬ćěF„ŠM¦ći..͵ŢY“€`+iEäˇŢvĺlZôţć¬zůHsC2Ľ Ô 8§äl@^žĽe§iKEK®Eăe.«g—>Ŕ`,ĄJ•}Ź6,X†ĺf«Ô˘ăsę(k¦Ě gÓ Đ‘˝Ňu/t.eŘ´µŘ‰!´«)kMˇ+%M%É>öŚĽE'ŕ§Žb`±ę‹f’žĚőŤ&¦mÓKHÓô^‡vĚ@=B-y"/ÚĚŞÇ`,ĄJ•]ů)ŚP1ě4|زĘO-=0ŤÓöYˇ3-%Ť%)‹C[‹MKGÔÓťZt””}ě†{ KąziKŔĚŰ„U3RM˛“]“.ýY%@­zJ*×rKX5#Őmč «xQ°Ţë\*aĂgF1Ú&VŹÁXJ•>ß–(%şšź[µ§«ů–śî–8-QIa›˝f‘j€€¶.oÓÓ«[%`›8-:F碲 oŐ3d¦hß<‚Č‹ÔÂWŮš— `É·IpZÉÇęY?čS@˱’Ď`Ř‘*UZć€ÚČćňšçěľE;SŔ´aÓ řhĽNĄë^6¨ŢŚĘ’dçmZćöŹQR µ~Ńc*]ńň@gôÎćâ±r¶«Â(Ąś]Ó^V=ęIď¬aÇ•’8mÄä-Út&™łk6ÁŚd 0K©RĄE“3á4Žäަs¶«™¤uŔ˘ĺfć=ŰäťĂÝ™Fey¨| ¦­jŰßĘeŢłÍň ťgä¬yŰU.÷ ŐŞ—‹Ő›‘h<_Ąë^Pn&mÄĄé¨0ZŃbŐk¤š]$Ŕ`,ĄJ•Í;G—}ňQJÖ°hö¦|öE»XőPnn‘ŹÓRi¬–Ŕâ…A-=F<Ái[í(˙{÷Úö}çqüŁĂ9ôńa…¤Hˇ9ü5M©Ľ´TjrÄß^ËUiĘÍn±ÓŔl§Ł±×p'gGkąĄŘiŮât\k7ĐY-×F-K,.s ÍIË,—Ô±nö±tň¸Ë#_s-•Ŕ‰%ŕűăë|ŁŘ_Év˘ţ8ĎÇA‘ľúúóyë+˝ľßďçűCܨŔ•/ĚÜqs@ka<Ďř÷łÉőtWąuI××ËJŐĘýŞök4´ÎIšŐÍń ăß…sqĚďä­÷Rşy“-ůÝrď¨Ý7ď™$Ě3ŐŚ‘­ś{,­ź1­Ş…ű„-|â×s–Š˙˝9¦e†ôÍŃľu3˘s]Ř«nVŔX$ŚgÎŁĎąôâú<[XbŤ†VřĂ»q#: ˇSˇJ7Xsţ¦Ň `Ą-€4-€4-€4ÖčK[·n]ôŚű÷Xl¬¸%v!ćńx›ĹťíťcK ’¸Vé¬eç.3ş’Łč‰%„h˙~űÔ_¦Š>Ű;GhA±ńíom•nĹEq`ź×Ý_gśĚ=Ő׌óV·nÝ>Ö4­îţşłgÎ'g’-Zę¨ľ˙Xż1Ą¦iˇŹBőŐsí­í}Ż÷UŞ;ů”6´FĎŚjŹiJµbłŮ‡Ö ĹĆců&ŽśŹ¤ľJ·±ńÍV±ďóŞşo©5)ŰőÖWşQ9ńîň*ĘÂňŕÝĺŤ]XÝňPXe—vT\ŰÁ6ĎOŕĺ@6›í{˝oŕÍsü'ř^p蝡CĎęęîJĄSâşhkmsowO'¦Ç~5=<1(„™™9=2:2:==-„î˙Q{d©„ˇŐ˙ăţý­ű›÷5_™ľ2˙×ů‰‰ ˙żÝž÷\ý§źžüb˛¸mđ<ě)ņóJ¬¶ű–JQ“˛ĎçH\JTşE•”L&źţîÓĎw|óßĚ˙u>‘H{íXMMM˙D—v”Y—żkkŽ©?/ěÇx{`üÓń–-ÚNMŰ­™ÓzŢť^˙üâşśśŚ˙>>33ă?âUÂĺtµ}Ż-üó…sů»_ěvďpŻö—ŞśJZş®}ýč[Çß Ľplq BUŐ¶Ö6­ABß ŞŰUĄZqlq„> !|Oř„MŤM—Břgqď.Żc‹ĂµÍeL „H\JřžđŐ»ë].—Íf‹śŹ!’_&}{}Ƭ/Śťűęv5řNбĹ1xbpŹoŹńvËyö˝Öçrą”jĹáp„Ţ/Ú wßfł™›\ćăĄ-YT“|= Ź„ŐíŞ˘(Áw± 1‡Ăáp8F?-Đkł>± ±U €eŰlłŮ‚ďŐíŞĂáXzŃĄuhúN“˙‡~s×6Wüłxľľ—s1Če\Ć·őŮVĄZ„Ëĺjz¦É»Ëkvyé"aY‡Ĺ™üďÉÂK{e?wѢ1-÷năyµVő<ě™üýdî7Bát9…އ"ťNĎęłB—Ó¸¸p9]ł_ĎŹk¶sEŞJZĆ~ʶÖ÷u?čžOdć2˝=˝î€Âř–F˘‘·R©TScS÷‘îÔW©Č'‘ÎĂťÉ/“™LfĎS{Zöµ$¦ş®/lö^ľ§|îíîĚ7™ÄŁŹöëBĚüe&řApěWc »Śżh9ĎÄĄÄńcÇ㿉gć2W®\iŢ×\žî/eŮ’Üščéŕ‰ÁČ'‘ŢW{ÝĐéP"‘h|¦qđÍÁ|˝Î­Ź}Ł˝D( p› '§ÂţńwîLĄrvZŐˇő{­#?1Rš˝šő<ě|{pé«ú׺˘v[­‘aćĄlőYÝąŮYÎvމR…V:ťB¸6»,_ő=áslqdć2ŞŞS択ŹfłYUUăăŮ«YçfgôB4öëŘěěěˇĘť2ţŰřĚĚLßŃ>cŐµăůŽĐG ëŚÇ^;ćőx•ŤJy:j˘J üt q)ˇ(ŠcKŃî,ÜýĄ–mIážÖ»ëµ-›Íž žtą\ÚnÍh€eŻÍwy=^ő^µDB´·µçŽiMLN/hłˇ˙GýZć?âĎfłńßà ׎y_söj6öiLü xčůCůú^ćĹŕDü7ńľžľŃŹGëîŻS·«od2™Âo˛¬Cľâ*űąŁRڎ¬·Ţ|k蝡č/ŁŃóŃ›Ż]BĐG!ç˝NďĂ^m§V[[üiP\ú¬:j~vńŠ‹ÝnOµřÇy-(ŐyZĆÎz}Vwmłřá˝ ~tow§ç,Šbäżą¦ íÖś.çĚĺűF»˘(ąS&/'….WÎFîěÂFî˘Ó ,çéÚ拎őżŃ˙퇾í~Ŕ}ňý“Úcš(†ÂÝ_jŮ–č©ĚBĄú–úXöÚxlÔ§tB ‡‡ŰZ­·5 ´Ů`ôÔHýt*­¸¦±¬R­4ďkťyvz˘çŁ''Ežľ›8e[ Ű :^ččxˇ#3—9{îlŕ•ŔřĹńČąHw,Şĺ“fqL•ýÜQ]ţ®.Wî3úăź>üčCm§ćÝéBôöô^ 444»÷Řoßhwßçź żúá‘pŕĺ@]}ťÝnoŢ×Ü׳ř(A˙׿u d–ćYe•*´Śńŕ{Áţ7|’JtîśžžVU56‹ţWtŃŞŞfŻg‡O çţśŤžÍ^Ífć2Jµ’L&Ťu›*„ĐuÝřëłşÓi˝‘k9O!„oŻĎ·×—JĄŻZ´ëV7şźKż|óĎnÉĘ{zË»ňôú–¦–¦EaěÍP·©Ůë ÷ÉW‡Ö­űě÷ěđ4>Ůhl7X/EŹ–s1ČG©VÚZ۲WłťţÎE/ĺ.7źĽQË'Íâd˙ÜQŘ•+W,źďîé6űŹřýGnkýâě/rŹËB¨µęčŽs÷‹ÝÝ/v‹µ§T»]Ű\˝Żö˙ÉńŔËÄT"3—I~™ ľŚśŹ¤żN !ôY=őUjǫ̂ÂŘ/oßhO}ťB4ţscí˝µćţz]דɤďź|˘J=v4q)a¬ż+Uж[«˝Ż¶˙'ýâšĐ/ëˇB;,Űc9Ďd2żׄĂápßç.O÷ŤžN|>‘¸”0o虯%fMVŢÓe{ť;Aé*p§® !Äŕ‰Aç˝ÎÜ/[ľ:4=Ůd·Ű{z{˝°°ٲďe^ rĹ/ĆűÜ?ńůDf.#„Đ/ëá3á†Ý c®K‰BuČS“Äź;°śRňţF˙đφăăŹxůÖß}Ë«ycźĆÔZU{Lk=ŘúčăŹz˙ÁëŰëóěô<úřŁBŢžŢöçÚ犢Äb±ô\zëßoUŞMÓ_$[ááŕ{ÁG´Gş_ęUÂn·‹ "ŤM]šR6)őŢú–}-ůÎ*°śgćj¦ë‡]Ę&E©VFÎŚ,]ď(E÷…˝Żööôö457™ŰaůZbÖdĺ=]¶×ą”´‹Ć´l6ŰĘWç÷<µG©Vbă±Č'±!ç…|uŘ Zźmunv6=ŮdLhŮ÷ň/¦šÍ5Sžj®}Ó=›l6[˝·^ݦFÎ.ě\şH¨CŢâÜPŮĎkÍPph=­šŘ„óóóćŻIěB,úëhřT¸ŔďKô\´ń™Fs\ˇÜ®‰T:µéžMÓ˙3­nW—ꞱŮlc±1cëĘ5}§ÉăńŢ+Ë:Ü^q°rş®?qEźsŕ•@áźÖuIźŐO üűŔí˝±ńÉƶçÚŚ˘M}1µç©=Ň\07q)‘N§=;=٫ٮî.÷7‰SňËdô—ѡw‡*ÝĄ%͵ÓétçżvnşgS]}]v.ů¤Đ1WÚđφ=;<«zK&›«ęşZʱ¬ĂmXO¤ŮŇŇÓîňëÝ=ڰőÖŻżkZÖá6Š5Ĺ<Ą·GšĐٱÎqç-(‡Ű8KI3¦ˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇFŐmżS×ő"¶€eÝfhEĎE‹Ű–u;ˇŐřLcŃŰŔ˛ÓHĐHĐHĐHĐHĐHĐHĐHĂúäâ‰É‰2·€eY‡Öŕ‰Á2·€eY„–ď}ĺoŠ(÷:[\%Ŕzb˝Ąĺv»ËÜËÔÔÔ˘g¸V$Y®ss @„@UBŘ…X2™¬tK¸E6›5Şóp§0¶´jjj<7T¸ä¨©©QUUUŐ“˙qRb¤Ó銶 €ĺ1¦ˇˇˇˇˇˇˇˇˇˇˇ†őť‹—Ţýň˛Ľű'Čhqh©ŞşÚ{kŮíöâµE»3óéX;\.ת"Ćăń,ş ‰m~~ŢfłýáwČ}ˇ¦¦f…sL§Óľ˝ľ•·pךř|bUÓ›Á”L&;wÎĎĎ[ď\ůíµ’É¤®ë«jŕ®u‡·o¬B[ĆM!UU-N»¸cĆîDc3K»Ťl6›®U!ç+´ÚĂ&:w !nF•ůhá˙6[±ZŔZR˙Šk±ůŃcIEND®B`‚mdbtools-0.7.1/src/gmdb2/help/C/gmdb-C.omf000066400000000000000000000015341222645741400200440ustar00rootroot00000000000000 camber@ais.org (Brian Bruns) camber@ais.org (Brian Bruns) gmdb Manual V1.0 2003-01-10 User manual for gmdb2. user's guide mdbtools-0.7.1/src/gmdb2/help/C/gmdb.xml000066400000000000000000000412771222645741400177130ustar00rootroot00000000000000 ]>
    &app; Manual V&manrevision; 2003 Brian Bruns MDB Tools Project &legal; Brian Bruns MDB Tools Project
    camber@ais.org
    gmdb V0.5 2000 Brian Brunscamber@ais.org MDB Tools Project This manual describes version &appversion; of &app;. Feedback To report a bug or make a suggestion regarding this application or this manual, follow the directions in this document.
    gmdb2 Introduction The &app; application is the graphical interface to MDB Tools. You can use &app; to view and export data and schema from MDB databases. Getting Started To Start &app; from the Command Line To start &app; from the command line, type the following command, then press Return: gmdb2
    &app; Window Screenshot of the gmdb2 main window.
    The &app; window contains the following elements: Menubar. The menus on the menubar contain all of the commands you need to work with databases in &app;. Toolbar. The toolbar contains a subset of the commands that you can access from the menubar. Tabbed window. The tabbed window contains a tab for each type of object in the database. Within these, a listing of those objects will be displayed along with buttons along the left hand side for performing common actions specific to that type of object. Statusbar. The statusbar displays information about current &app; activity and contextual information about the menu items. When you right-click on any icon in the &app; icon list, the application displays a popup menu. The popup menu contains the full list of available actions that may be performed on that object.
    To Open a File To open a file, choose File Open to display the Open File dialog. Select the file that you want to open, then click OK. The file is displayed in the &app; window. The application also records the paths and file names of the last four files that you edited and displays them as menu items on the File menu. To open one of the last four files, choose for example File 1. /path/filename . To Open Files from a Command Line You can run &app; from a command line and open a file. To open a file from a command line, type the following command, then press Return: gmdb2 file1.mdb When the application starts, the file that you specified is displayed in the &app; window. &app; uses the environment variable MDBPATH when looking for the specified file. If set &app;will search each directory component until the file is found.
    Usage To Display the Properties of a Database To display the properties of a database, perform the following steps: Choose File Properties To Export the Schema of a Database To export the schema of the current database, Choose Tools Export Schema and perform the following steps: Select the filename to save the schema in. If you want to only export one table, select it. Choose the SQL dialect of the target database backend. Check desired schema options. Click Export. Checking the Include Relationships box will generate foreign key relationships if they are supported by the database. Checking the Include Drop Table commands will generate the commands to drop the tables before creating new tables. To Open a SQL Query Window The SQL Query window allows you enter SQL queries and to execute and view the results. To open the SQL Query window, perform the following steps. Choose Tools SQL Window To Open a File Debugger Window The File Debugger window allows you enter SQL queries and to execute and view the results. Choose Tools Debug Window Preferences To view or set Preferences choose Edit Preferences from the menu. Maximum Rows to Display This option limits the number of rows that will be returned when Clicking the Data button on the Tables tab window, or Running a SQL select in the Query Window By extension, this also affects the number of rows saved when saving the results of a SQL query. If no value is set, the default number of rows displayed is 1,000. This option may be disabled by setting the value to 0, but be warned that attempting to display a large number of rows will result in an increased delay proportional to the number of rows. Table Actions To perform actions on a table choose the Tables tab from the main window. Table Definition To view the definition of a table, perform the following actions Locate the desired table in the tables icon list. Select the tables icon. Click on the Definition button from the right hand side of the icon list. Columns participating in a Primary Key will have an icon of a gold key and the letters PK at the left side of the column. Data View The Data view displays a grid of the data in a table. To display the table data, perform the following steps Locate the desired table in the tables icon list. Select the tables icon. Click on the Data button from the right hand side of the icon list. Data Export The Export button creates a text file containing the data from a single table. To export the table data, perform the following steps Locate the desired table in the tables icon list. Select the tables icon. Click on the Export button from the right hand side of the icon list to display the Export Table window. Select the filename to save the data in. Fill in dialog with desired characteristics of the export file. Click Export. Checking the Include Headers box will write a single row at the top of the file with the names of the columns. Query Window To open the SQL query window choose Tools SQL Window
    &app; Query Window Screenshot of the gmdb2 query window.
    The &app; Query window contains the following elements: Menubar. The menus on the menubar contain all of the commands you need to work with SQL queries and their results in &app;. Toolbar. The toolbar contains a subset of the commands that you can access from the menubar. Table List. The table list contains a list of tables for the current database that can be dragged into the query editor. Query Editor. The query editor is a text editing window where you can write your SQL select. Recent Queries List. The recent queries list can be used to bring a previously run query back into the query editor. Results Window. The results window shows the results of the last SQL query executed. To Open a New Query Window To open a new query window, choose Query New To Load a Query from a File To load a query from a text file, choose Query Open To Save a Query to a File To save the current query to a text file, choose Query Save The active file can be found in the title bar of the window. If this is not the desired file, choose the Save As menu item. To Load a Query from a File To load a query from a text file, choose Query Open
    mdbtools-0.7.1/src/gmdb2/help/C/legal.xml000066400000000000000000000077021222645741400200610ustar00rootroot00000000000000 Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License (GFDL), Version 1.1 or any later version published by the Free Software Foundation with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. You can find a copy of the GFDL at this link or in the file COPYING-DOCS distributed with this manual. This manual is part of a collection of GNOME manuals distributed under the GFDL. If you want to distribute this manual separately from the collection, you can do so by adding a copy of the license to the manual, as described in section 6 of the license. Many of the names used by companies to distinguish their products and services are claimed as trademarks. Where those names appear in any GNOME documentation, and the members of the GNOME Documentation Project are made aware of those trademarks, then the names are in capital letters or initial capital letters. DOCUMENT AND MODIFIED VERSIONS OF THE DOCUMENT ARE PROVIDED UNDER THE TERMS OF THE GNU FREE DOCUMENTATION LICENSE WITH THE FURTHER UNDERSTANDING THAT: DOCUMENT IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE DOCUMENT OR MODIFIED VERSION OF THE DOCUMENT IS FREE OF DEFECTS MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY, ACCURACY, AND PERFORMANCE OF THE DOCUMENT OR MODIFIED VERSION OF THE DOCUMENT IS WITH YOU. SHOULD ANY DOCUMENT OR MODIFIED VERSION PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL WRITER, AUTHOR OR ANY CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY DOCUMENT OR MODIFIED VERSION OF THE DOCUMENT IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER; AND UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER IN TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL THE AUTHOR, INITIAL WRITER, ANY CONTRIBUTOR, OR ANY DISTRIBUTOR OF THE DOCUMENT OR MODIFIED VERSION OF THE DOCUMENT, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER DAMAGES OR LOSSES ARISING OUT OF OR RELATING TO USE OF THE DOCUMENT AND MODIFIED VERSIONS OF THE DOCUMENT, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. mdbtools-0.7.1/src/gmdb2/help/Makefile.am000066400000000000000000000001101222645741400201070ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in. SUBDIRS = C mdbtools-0.7.1/src/gmdb2/info.c000066400000000000000000000073431222645741400162410ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * 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. */ #include "gmdb.h" extern GtkWidget *app; extern MdbHandle *mdb; typedef struct GMdbInfoWindow { GtkWidget *window; } GMdbInfoWindow; GMdbInfoWindow *infow; /* callbacks */ GtkWidget * gmdb_info_new() { GtkWidget *propswin, *label; GladeXML *propswin_xml; gchar title[100]; gchar tmpstr[20]; gchar *filename, *filepath; int i; struct stat st; char* version; MdbCatalogEntry *entry = mdb_get_catalogentry_by_name(mdb, "SummaryInfo"); /* load the interface */ propswin_xml = glade_xml_new(GMDB_GLADEDIR "gmdb-props.glade", NULL, NULL); /* connect the signals in the interface */ glade_xml_signal_autoconnect(propswin_xml); filepath = g_strdup(mdb->f->filename); for (i=strlen(filepath);i>0 && filepath[i-1]!='/';i--); filename=&filepath[i]; propswin = glade_xml_get_widget (propswin_xml, "props_dialog"); g_snprintf(title, 100, "%s Properties",filename); gtk_window_set_title(GTK_WINDOW(propswin), title); label = glade_xml_get_widget (propswin_xml, "props_filename"); gtk_label_set_text(GTK_LABEL(label), filename); label = glade_xml_get_widget (propswin_xml, "props_jetver"); switch(mdb->f->jet_version) { case MDB_VER_JET3: version = "3 (Access 97)"; break; case MDB_VER_JET4: version = "4 (Access 2000/XP/2003)"; break; case MDB_VER_ACCDB_2007: version = "ACE 12 (Access 2007)"; break; case MDB_VER_ACCDB_2010: version = "ACE 14 (Access 2010)"; break; default: version = "Unknown"; } gtk_label_set_text(GTK_LABEL(label), version); label = glade_xml_get_widget (propswin_xml, "props_encrypted"); gtk_label_set_text(GTK_LABEL(label), mdb->f->db_key ? "Yes" : "No"); assert( fstat(mdb->f->fd, &st)!=-1 ); sprintf(tmpstr, "%zd K", (size_t)(st.st_size/1024)); label = glade_xml_get_widget (propswin_xml, "props_filesize"); gtk_label_set_text(GTK_LABEL(label), tmpstr); sprintf(tmpstr, "%zd", (size_t)(st.st_size / mdb->fmt->pg_size)); label = glade_xml_get_widget (propswin_xml, "props_numpages"); gtk_label_set_text(GTK_LABEL(label), tmpstr); sprintf(tmpstr, "%d", mdb->num_catalog); label = glade_xml_get_widget (propswin_xml, "props_numobjs"); gtk_label_set_text(GTK_LABEL(label), tmpstr); if (entry && entry->props && entry->props->len) { // There is only one MdbProps for that kind of entry MdbProperties *props = g_array_index(entry->props, MdbProperties*, 0); const char *propval; propval = g_hash_table_lookup(props->hash, "Title"); if (propval) { label = glade_xml_get_widget (propswin_xml, "props_title"); gtk_label_set_text(GTK_LABEL(label), propval); } propval = g_hash_table_lookup(props->hash, "Company"); if (propval) { label = glade_xml_get_widget (propswin_xml, "props_company"); gtk_label_set_text(GTK_LABEL(label), propval); } propval = g_hash_table_lookup(props->hash, "Author"); if (propval) { label = glade_xml_get_widget (propswin_xml, "props_author"); gtk_label_set_text(GTK_LABEL(label), propval); } } g_free(filepath); return propswin; } mdbtools-0.7.1/src/gmdb2/main2.c000066400000000000000000000113371222645741400163120ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000-2004 Brian Bruns * * 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. */ #include #include #include #include "mdbtools.h" #include "mdbver.h" #include "mdbsql.h" #include "gmdb.h" GtkWidget *app; GladeXML *mainwin_xml; MdbSQL *sql; /* called when the user closes the window */ static gint delete_event(GtkWidget *widget, GdkEvent *event, gpointer data) { /* signal the main loop to quit */ gtk_main_quit(); /* return FALSE to continue closing the window */ return FALSE; } void gmdb_about_cb(GtkWidget *button, gpointer data) { const gchar *authors[] = { "Brian Bruns", "Jeff Smith", "Filip Van Raemdonck", "Bernhard Reiter", "Nirgal Vourgère", NULL }; const gchar *documenters[] = { "Brian Bruns", NULL }; GtkWidget *parent; GdkPixbuf *pixbuf=NULL; FILE *flicense; guint32 licenselen; char *license; parent = gtk_widget_get_toplevel (button); if (!GTK_WIDGET_TOPLEVEL (parent)) parent = NULL; if (!pixbuf) pixbuf = gdk_pixbuf_new_from_file (GMDB_ICONDIR "logo.xpm", NULL); flicense = fopen(GMDB_ICONDIR "COPYING", "r"); if (flicense) { fseek(flicense, 0, SEEK_END); licenselen = ftell(flicense); fseek(flicense, 0, SEEK_SET); license = g_malloc(licenselen+1); fread(license, 1, licenselen, flicense); license[licenselen] = 0; fclose(flicense); } else { fprintf(stderr, "Can't open " GMDB_ICONDIR "COPYING\n"); license = NULL; } gtk_show_about_dialog ((GtkWindow*)parent, "authors", authors, "comments", _("GNOME MDB Viewer is a grapical interface to " "MDB Tools. It lets you view and export data and schema " "from MDB files produced by MS Access 97/2000/XP/2003/2007/2010."), "copyright", _("Copyright 2002-2012 Brian Bruns and others"), "documenters", documenters, "logo", pixbuf, "program-name", _("GNOME MDB Viewer"), "version", MDB_VERSION_NO, "website", "http://mdbtools.sourceforge.net/", "license", license, NULL); g_free(license); } void gmdb_prefs_cb(GtkWidget *button, gpointer data) { gmdb_prefs_new(); } void gmdb_info_cb(GtkWidget *button, gpointer data) { gmdb_info_new(); } void gmdb_help_cb(GtkWidget *button, gpointer data) { GError *error = NULL; gnome_help_display("gmdb.xml", NULL, &error); if (error != NULL) { g_warning ("%s", error->message); g_error_free (error); } } void gmdb_load_recent_files() { GtkWidget *menuitem; GtkWidget *menulabel; char menuname[100]; char cfgname[100]; int i; gchar *text, *text2; for (i=4;i>=1;i--) { sprintf(menuname, "menu_recent%d",i); sprintf(cfgname, "/gmdb/RecentFiles/menu_recent%d.basename",i); menuitem = glade_xml_get_widget (mainwin_xml, menuname); menulabel = gtk_bin_get_child(GTK_BIN(menuitem)); text = gnome_config_get_string(cfgname); if (!text) { gtk_widget_hide(menuitem); } else { text2 = g_malloc(strlen(text)+4); sprintf(text2,"%d. %s",i,text); gtk_label_set_text(GTK_LABEL(menulabel),text2); gtk_widget_show(menuitem); g_free(text2); } g_free(text); } } int main(int argc, char *argv[]) { GtkWidget *gmdb; #ifdef SQL /* initialize the SQL engine */ sql = mdb_sql_init(); #endif /* Initialize GNOME */ /* Initialize gnome program */ gnome_program_init ("gmdb", MDB_VERSION_NO, LIBGNOMEUI_MODULE, argc, argv, GNOME_PARAM_POPT_TABLE, NULL, GNOME_PARAM_HUMAN_READABLE_NAME, _("Gnome-MDB File Viewer"), GNOME_PARAM_APP_DATADIR, DATADIR, NULL); //gnome_init ("gmdb", "0.2", argc, argv); //app = gnome_app_new ("gmdb", "Gnome-MDB File Viewer"); glade_init(); /* load the interface */ mainwin_xml = glade_xml_new(GMDB_GLADEDIR "gmdb.glade", NULL, NULL); /* connect the signals in the interface */ glade_xml_signal_autoconnect(mainwin_xml); gmdb = glade_xml_get_widget (mainwin_xml, "gmdb"); gtk_signal_connect (GTK_OBJECT (gmdb), "delete_event", GTK_SIGNAL_FUNC (delete_event), NULL); if (argc>1) { gmdb_file_open(argv[1]); } gmdb_load_recent_files(); /* start the event loop */ gtk_main(); #ifdef SQL /* free MDB Tools library */ mdb_sql_exit(sql); #endif return 0; } mdbtools-0.7.1/src/gmdb2/pixmaps/000077500000000000000000000000001222645741400166145ustar00rootroot00000000000000mdbtools-0.7.1/src/gmdb2/pixmaps/Makefile.am000066400000000000000000000005341222645741400206520ustar00rootroot00000000000000 appicondir = $(datadir)/gmdb/glade appicon_DATA = \ pk.xpm \ logo.xpm \ debug.xpm \ table.xpm \ query.xpm \ forms.xpm \ reports.xpm \ macros.xpm \ code.xpm \ table_big.xpm \ query_big.xpm \ form_big.xpm \ report_big.xpm \ macro_big.xpm \ module_big.xpm \ stock_export.png \ stock_export-16.png EXTRA_DIST = $(appicon_DATA) mdbtools-0.7.1/src/gmdb2/pixmaps/code.xpm000066400000000000000000000006371222645741400202620ustar00rootroot00000000000000/* XPM */ static char * code_xpm[] = { "16 16 3 1", " c None", ". c #000000", "+ c #777777", " ", " ", " .. ", " .++. ", " . . . ", " . .. ..", " . .+ +.", ".... . .+ +. .", " . . .+. .", " . .+ +.+ +.", " . .. +. .+ ..", " . . . . . ", " ", " ", " ", " "}; mdbtools-0.7.1/src/gmdb2/pixmaps/debug.xpm000066400000000000000000000006571222645741400204400ustar00rootroot00000000000000/* XPM */ static char * debug_xpm[] = { "16 16 4 1", " c None", ". c #ED2D2D", "+ c #635757", "@ c #000000", " ", " ..... ", " ... ... ", " .. +@+ .. ", " .... @@@ .. ", " .@+..+@+ +@. ", ".. @+..@@ +@ .. ", ". @@..@@@ . ", ". @@..@ . ", ". @@@@@@..@@@ . ", ".. @@@@.. .. ", " . @@@@@@.. . ", " ..@+ @@@ +... ", " .. .. ", " ... ... ", " ..... "}; mdbtools-0.7.1/src/gmdb2/pixmaps/form_big.xpm000066400000000000000000000103301222645741400211230ustar00rootroot00000000000000/* XPM */ static char * form_big_xpm[] = { "20 20 211 2", " c None", ". c #585858", "+ c #635C56", "@ c #B97943", "# c #EAB476", "$ c #747474", "% c #808080", "& c #707070", "* c #645C55", "= c #816751", "- c #CB8E57", "; c #F0AE62", "> c #B6B6B6", ", c #E0E0E0", "' c #E1E1E1", ") c #DFDFDF", "! c #DEDEDE", "~ c #DAD4CE", "{ c #CD894D", "] c #F5BA7A", "^ c #FD9D2E", "/ c #EDEDED", "( c #FCFCFC", "_ c #E7E7E7", ": c #DDDDDD", "< c #CAA88C", "[ c #D39155", "} c #F5BA77", "| c #FD9325", "1 c #FE8A09", "2 c #EEEEEE", "3 c #FFFFFF", "4 c #E8E8E8", "5 c #FDFDFD", "6 c #FDFCFB", "7 c #EFE5DC", "8 c #D2AB8C", "9 c #D8A371", "0 c #EFAB63", "a c #FC9930", "b c #FE8A0B", "c c #F58104", "d c #E6E6E6", "e c #E3E3E3", "f c #FAF8F5", "g c #EFE5DB", "h c #D7AF8E", "i c #DBA470", "j c #EDA45A", "k c #FC9E39", "l c #FC8709", "m c #F28004", "n c #D56C04", "o c #EBE8E7", "p c #F1E4DB", "q c #E0BEA2", "r c #D4965F", "s c #EFAA61", "t c #FC9D38", "u c #FB8508", "v c #F27F03", "w c #D46C04", "x c #954803", "y c #E9E9E9", "z c #E6DDD8", "A c #E6C6B1", "B c #DB9B6B", "C c #F4BC85", "D c #FC962D", "E c #FC8505", "F c #D66D04", "G c #9D4A04", "H c #431F02", "I c #F1F1F1", "J c #EFE1D7", "K c #F5D7C2", "L c #F9D3B8", "M c #EE9E6E", "N c #F68725", "O c #F07D06", "P c #D36C03", "Q c #9B4904", "R c #3A1B02", "S c #EAD1C2", "T c #F3D4BC", "U c #F9D7BD", "V c #F2BB9B", "W c #DD8154", "X c #DB712A", "Y c #C86312", "Z c #944806", "` c #472102", " . c #EFEFEF", ".. c #E2E1DD", "+. c #E9CBB6", "@. c #F6CFB2", "#. c #F4C7A8", "$. c #D79371", "%. c #B2673D", "&. c #9D5A2F", "*. c #7C421A", "=. c #51290E", "-. c #2A2019", ";. c #FCFAF8", ">. c #EAD7C9", ",. c #EECFB7", "'. c #F0C3A5", "). c #DCA282", "!. c #AB6D4D", "~. c #754D2D", "{. c #5D4733", "]. c #544234", "^. c #483A31", "/. c #303030", "(. c #FBFBFA", "_. c #F8F1EC", ":. c #E7B598", "<. c #ECBB9D", "[. c #D49B7C", "}. c #A86C4C", "|. c #785037", "1. c #463D32", "2. c #4C4946", "3. c #877D6F", "4. c #928673", "5. c #E1DDD9", "6. c #D8CCBC", "7. c #9B8770", "8. c #A47A5F", "9. c #825C46", "0. c #5A473B", "a. c #66605B", "b. c #9D9C99", "c. c #A5A5A3", "d. c #B1A797", "e. c #92846F", "f. c #E8E6E5", "g. c #DFD9D1", "h. c #A69A88", "i. c #474034", "j. c #5D4E43", "k. c #796B62", "l. c #8F8981", "m. c #A9A5A0", "n. c #C9C6C4", "o. c #D5CBBC", "p. c #CAB99F", "q. c #92836D", "r. c #E4DED6", "s. c #CDC2B1", "t. c #857A6A", "u. c #605A50", "v. c #7B746B", "w. c #A7A094", "x. c #CCC2B3", "y. c #D9CDBD", "z. c #E1D5C5", "A. c #E6D4BA", "B. c #D2BC9C", "C. c #928269", "D. c #E0D9CD", "E. c #CCBFA9", "F. c #9C9383", "G. c #B2A99B", "H. c #C5BAAA", "I. c #DDCFBA", "J. c #EDDCC3", "K. c #EBD8BD", "L. c #E9D5B7", "M. c #E7D1B0", "N. c #D1B995", "O. c #928066", "P. c #B4B4B3", "Q. c #E5E2DB", "R. c #EFE7DA", "S. c #EDE3D3", "T. c #ECE0CC", "U. c #EADBC6", "V. c #E9D8BF", "W. c #E7D4B8", "X. c #E5D1B2", "Y. c #E3CDAC", "Z. c #E2C9A5", "`. c #CEB48D", " + c #927F62", ".+ c #A7A49D", "++ c #C9C5BA", "@+ c #CAC4B7", "#+ c #C8C1B0", "$+ c #C8BDA8", "%+ c #C7B9A1", "&+ c #C5B59A", "*+ c #C4B293", "=+ c #C3AE8C", "-+ c #C2AA85", ";+ c #C1A67E", ">+ c #BEA177", ",+ c #927D5F", "'+ c #5B5A58", ")+ c #5D5B58", "!+ c #5D5B57", "~+ c #5C5A55", "{+ c #5C5953", "]+ c #5C5851", "^+ c #5B574E", "/+ c #5B564C", "(+ c #5B544A", "_+ c #5B5348", ":+ c #5A5246", "<+ c #5A5145", "[+ c #4D473E", " . . . . . . . . . . . . . . + @ # ", " . $ % % % % % % % % % % & * = - ; ", " . > , ' ' ' ) , ' ' ' ! ~ { ] ^ ", " . > / ( ( ( _ / ( ( ( : < [ } | 1 ", " . > 2 3 3 3 4 / 5 6 7 8 9 0 a b c ", " . > d 2 2 2 e / f g h i j k l m n ", " . > e 4 4 4 ' o p q r s t u v w x ", " . > 2 3 3 3 y z A B C D E m F G H ", " . > 2 3 3 3 I J K L M N O P Q R ", " . > e 4 4 4 S T U V W X Y Z ` ", " . > d ./ ..+.@.#.$.%.&.*.=.-. ", " . > 2 3 ;.>.,.'.).!.~.{.].^./. ", " . > / (._.:.<.[.}.|.1.2.3.4./. ", " . > , 5.6.7.8.9.0.a.b.c.d.e./. ", " . > f.g.h.i.j.k.l.m.n.o.p.q./. ", " . > r.s.t.u.v.w.x.y.z.A.B.C./. ", " . > D.E.F.G.H.I.J.K.L.M.N.O./. ", " . P.Q.R.S.T.U.V.W.X.Y.Z.`. +/. ", " . .+++@+#+$+%+&+*+=+-+;+>+,+/. ", " . '+)+!+~+{+]+^+/+(+_+:+<+[+/. "}; mdbtools-0.7.1/src/gmdb2/pixmaps/forms.xpm000066400000000000000000000044451222645741400204770ustar00rootroot00000000000000/* XPM */ static char * forms_xpm[] = { "16 16 107 2", " c None", ". c #585858", "+ c #C47D41", "@ c #FACB8D", "# c #DEDEDE", "$ c #C37B40", "% c #FAC78C", "& c #FE8F0C", "* c #FFFFFF", "= c #CECECE", "- c #FAC689", "; c #FE880E", "> c #FE8801", ", c #FCFCFC", "' c #FEFEFE", ") c #E5D6C8", "! c #FAC98F", "~ c #FD8810", "{ c #FE8803", "] c #EC7A03", "^ c #FDFDFD", "/ c #E7DACC", "( c #FD850C", "_ c #FE8703", ": c #E47604", "< c #A54E04", "[ c #ECDAD2", "} c #D38F5D", "| c #F8C58D", "1 c #FE8406", "2 c #FE8804", "3 c #A34C04", "4 c #1C0C01", "5 c #EDEDED", "6 c #F4D6C1", "7 c #FFE2CD", "8 c #EB9260", "9 c #FA800A", "0 c #E47702", "a c #A04A04", "b c #210F01", "c c #DFDFDF", "d c #EBB698", "e c #FEE5CA", "f c #F1B492", "g c #D37043", "h c #CF6524", "i c #A04B0A", "j c #231001", "k c #E4E0D8", "l c #EFD0B5", "m c #FFD1B1", "n c #C67E5D", "o c #87542B", "p c #5C4733", "q c #241008", "r c #303030", "s c #FDFDFC", "t c #EFB493", "u c #F7C9AC", "v c #C67D5A", "w c #825234", "x c #332E23", "y c #474544", "z c #BCAB90", "A c #DCD0BF", "B c #897862", "C c #A36F52", "D c #4C392C", "E c #5B5957", "F c #B0B0AF", "G c #BCA88A", "H c #FAF6F2", "I c #A09380", "J c #1A1812", "K c #534F4C", "L c #9F9C96", "M c #C4BFB9", "N c #DAD6D3", "O c #E9D6BA", "P c #BCA685", "Q c #DAC8AB", "R c #736A5A", "S c #9C9488", "T c #BDB4A4", "U c #EEDFC8", "V c #ECDAC0", "W c #E9D6B9", "X c #E7D1B0", "Y c #BCA37F", "Z c #F4EDE1", "` c #F2E8D8", " . c #F0E4D0", ".. c #EEDEC8", "+. c #ECDABF", "@. c #E9D6B8", "#. c #E5CCA7", "$. c #BCA178", "%. c #C6C1B6", "&. c #C4BDAC", "*. c #C3B8A3", "=. c #C2B39A", "-. c #C0AF91", ";. c #BFAA88", ">. c #BEA57F", ",. c #BDA076", "'. c #BC9E73", " . . . . . . . . . . . . + @ ", " . # # # # # # # # # $ % & ", " . # * * * # * * * = $ - ; > ", " . # * * * # , ' ) $ ! ~ { ] ", " . # # # # # ^ / $ ! ( _ : < ", " . # * * * # [ } | 1 2 : 3 4 ", " . # * * * 5 6 7 8 9 0 a b ", " . c # # # d e f g h i j ", " . # * * k l m n o p q r ", " . # * s t u v w x y z r ", " . # # A B C D E F F G r ", " . # H I J K L M N O P r ", " . # Q R S T U V W X Y r ", " . # Z ` ...+.@.X #.$.r ", " . %.%.&.*.=.-.;.>.,.'.r ", " . r r r r r r r r r r r "}; mdbtools-0.7.1/src/gmdb2/pixmaps/logo.xpm000066400000000000000000000163141222645741400203070ustar00rootroot00000000000000/* XPM */ static char * logo_xpm[] = { "93 73 16 1", " c None", ". c #B2B2B2", "+ c #C2C2C2", "@ c #848484", "# c #929292", "$ c #FFFC10", "% c #E2E2E2", "& c #D2D2D2", "* c #A2A2A2", "= c #6D6D6D", "- c #3A3A3A", "; c #F3F164", "> c #FFFFFF", ", c #F4F4F4", "' c #ECEB95", ") c #FAF86B", " + ", " .#+#. ", " +@.$$$.@+ ", " +**%$$$$$@-#+ ", " *#&$$$$$+=*.-=. ", " +#+$$$$$%#@&$$=-@+", " +#.$$$$$%*=+$$+=#@*+", " +**%$$$$$.=*$$&#@&#** ", " **&$$$$$+=*$$$##*==*+* ", " +=+$$$$$%@=$>).=*#-+,&=+ ", " +**$$$$$%*=.>>+#@*#-#>.@+ ", " +#*%$$$$$.=.$$&@#*@*+=>.# ", " .*&$$$$$&=#;$$*@*#@'$=%&@ ", " +@+$$$$$%@@;$$.=**@&$$**,#+ ", " +#.$$$$$$*=.$$+##*@.,&$&=,.. ", " +#.%$$$$$.=.$$;@#*@.%&@#=-&%@ ", " .@&$$$$$&=#$$$*=.#@'$@@%%==*=+ ", " .*.$$$$$&#@&$$.##*@.$$@-*.#+ ++ ", " ++ +@*$$$$$$#=.$$+=##@*$$$+@,-. ", " +****#* *#&$$$$$.=*$$;@@*@#'$$+.=,+* ", " +***#@*%+-. .@+$$$$$&@#$$;*=.*=&$$'@##-*# ", " +.*#------+.-*+ +=@+ +#.$$$$$%#@+$$.@#.=-@#+*=&,.##+ ", " .**--*%$$$*-&*=-=.@#.*.#.%$$$$$#=+$$+=**@==+%*---##+ ", " +@.=-@$$$$$$$@->+.%$..%==%$$$$$+=*$$;#@.@*+-#&#. +## ", " +**@--&$$$$$$$$&-%$$$$*-@+$$$$$&##&$$*@###&,=%@=+ ", " **#--.$$$$$$$$$$$-+$$$$%.$$$$$$@=+$$.@*#@+$$**>#+ ", " .*.=-#$$$$$$$$$$$$$=+$$$$$$$$$$.=.$$'##.@*$$$%=,.. ", " +#.=-=$$$$$$$$$$$$$$$=+$$$$$$$$+=#$$'#@.@@$$$$$=+,@ ", " .#@--&$$$$$$$$$$$$$$$$-+$$$$$$&@@&$$*@##@+$$$$&@=#@+ ", " ##--.$$.-*$$$$$$$$$$$$$-.$$$$$@@$$$.=*#@+$$$$$#@&%-# ", " *#-@$$&@#+#$$$$$$$$$$$$$=.$$$+=.$$'@#.@*$$$$$$#-.+@+ ", " *@-*$$#@&$&#$$$$$$$$$$$$$=.$$#@'$&#####%$$$$$$+@,-* ", " +=-.$*=+$$$+@$$$$$$$$$$$$$=+%=*$'@@.##&$$$$$$$$@%&* ", " @-@$##$$$$*=@$$$$$$$$$$$$$===+&#=..@.$$$$$$$$$@@,*+ ", " .=-$*@$$$+=++#$$$$$$$$$$$$+--#@#++@*$$$$$$$$$*@@-=. ", " +@-&&=$$$+=+ +#$$$$$$$$$$$*-=.+&.@#%$$$$$$$$+=.,+@* ", " *-=$@;$$&= +#$$$$$$$$$$%=%,*==+%$$$$$$$$$*--*#+ ", " +@-&$#*;$=+ +#$$$$$$$$$$$==-#+#$$$$$$$$$+=*,-- ", " +--$$$*#=* +#$$$$$$$$$$$+*-+&#$$$$$$$+@#%+*. ", " *-#$$$$$*=. +#$$$$$$$$$$$$$-.&#$$$$$%@@&,#*+ ", " +=-&$$$$$$$*@+ +@$$$$$$$$$$$$$-.&@$$$+*=+%.#+ ", " *-=$$$$$$$$$%##*#$$$$$$$$$$$$$-*&#$+=--*+#+ ", " @-.$$$$$$$$$$$+#$$$$$$$$$$$$$$-.&-@#&@'*-+ ", " .@-$+=.$$$$$$$$$$$$$$$$$$$$$$$$-.$@&$$@$$*+ ", " *-@$=%#@&$$$$$$$$$$$$$$$$$$$$$$-*$$$$'=+$.+ ", " +#-'.#$$+-@+$$$$$$$$$$$$$$$$$$$$-*$$$.=*@*#+ ", " +--$@&$$*++##%$$$$$$$$$$$$$$$$$$-*$$=#%$$.-+ ", " #-.&@$$%# +=$$$$$$$$$$$$$$$$$$-*$=+$$$+#. ", " +=-'*.$$.. +@$$$*.$$$$$$$$$$$$$-.#*$$$.# ", " #-@$@$$$#+ @&$$+=@$$$$$$$$$$$$$-#@$$$.* ", " +=-&&@$$&@ .*$$$=&#$$$$$$$$$$$$+-=&$$+# ", " .=-$#+$$*+ @%$$*.%#$$$$$$$$$$$$#-@$$$@+ ", " .-@$=$$$= .+$$%=$%#$$$$$$$$$$$$--.$$.* ", " .-.$@$$+* +@$$$#.$%#$$$$$$$$$$$+-=%$$#+ ", "+*-''@$$*+ @+$$&@$$%@$$$$$$$$$$%-=*$$%# ", "+@-$$=$$@+ +#$$$@&$$+-$$$$$$$$$$@-=%$$.+ ", "+#-%$#.$#+ #%$$.#$$$==$$$$$$$$$+-=.$$%# ", "+*-+$$=%*+.*$$$=$$$.##$$$$$$$$%-=@$$$*+ ", "+.-=$$+=%==%$$#*$$$@ #%$$$$$$+-==$$$+@ ", " .+-&$$##-.$$&@$$$*+ #%$$$$$@-==%$$%@ ", " *+=-$$$@#$$$#+$$&# #$$$$+--@=%$$$#+ ", " @%-=$$$$$$&=$$$@+ =.$$%=-@@@$$$$#+ ", " +*&-*$$$$$=%$$+=.@'$$@--*@*$$$&@+ ", " *+*-%$$$.*$$$-=+$$*--@#*%$$$.#+ ", " @%=-$$$*@+#=*$$&--#@@%$$$+@. ", " +#%-=$$$*@*$$'@-=*=.$$$&.#+ ", " +.&-.$$$$$$@-=#@*$$$$*#+ ", " *+*-*$$$*--#@#%$$$+@+ ", " @&*-----##@&$$$&#. ", " +@+%+*.*@.$$$%.#+ ", " +*==.*.$$$$.*+ ", " +@#&$$$.@+ ", " +####. "}; mdbtools-0.7.1/src/gmdb2/pixmaps/macro_big.xpm000066400000000000000000000112511222645741400212640ustar00rootroot00000000000000/* XPM */ static char * macro_big_xpm[] = { "20 20 240 2", " c None", ". c #564F44", "+ c #554D42", "@ c #544C42", "# c #585148", "$ c #786F60", "% c #7B7162", "& c #756A5C", "* c #756B5E", "= c #635B4E", "- c #695F51", "; c #665C50", "> c #625B4F", ", c #857A69", "' c #8A7E6C", ") c #867968", "! c #807565", "~ c #817666", "{ c #70685C", "] c #7A7062", "^ c #9B8C77", "/ c #8E816E", "( c #877B69", "_ c #928470", ": c #B09E86", "< c #A5957E", "[ c #897B69", "} c #B2A188", "| c #BFAC91", "1 c #B5A38A", "2 c #8E806D", "3 c #998A74", "4 c #A0907A", "5 c #9A8A75", "6 c #6E6558", "7 c #807465", "8 c #BCA990", "9 c #A89781", "0 c #9D8E79", "a c #B3A189", "b c #CAB69A", "c c #BCA98F", "d c #9C8C78", "e c #C0AD92", "f c #CEB99C", "g c #C6B397", "h c #9D8E78", "i c #AC9B83", "j c #B8A68C", "k c #B6A38A", "l c #938674", "m c #6D6356", "n c #847767", "o c #D4BEA1", "p c #BBA88F", "q c #AC9B84", "r c #C2B095", "s c #D6C1A3", "t c #C8B499", "u c #AB9A83", "v c #C7B398", "w c #CEBA9D", "x c #C5B196", "y c #A4947E", "z c #AF9E85", "A c #B8A58C", "B c #908371", "C c #807667", "D c #6E6456", "E c #857867", "F c #D6BFA2", "G c #BFAB92", "H c #AF9E86", "I c #BFAD93", "J c #D7C1A4", "K c #D0BB9E", "L c #B9A78D", "M c #CDB99D", "N c #C4B096", "O c #9E8E78", "P c #9C8D76", "Q c #92836F", "R c #8C7E6B", "S c #897C69", "T c #8A7C69", "U c #645A4E", "V c #7C7061", "W c #D3BDA0", "X c #B5A28A", "Y c #B2A088", "Z c #D5BFA1", "` c #D1BC9E", " . c #B6A48B", ".. c #C8B498", "+. c #B1A087", "@. c #998B75", "#. c #A99980", "$. c #BFAC90", "%. c #CBB799", "&. c #C9B599", "*. c #BAA88F", "=. c #827665", "-. c #5D554A", ";. c #74695B", ">. c #C5B297", ",. c #978873", "'. c #CCB89B", "). c #B6A48A", "!. c #C4B195", "~. c #B09F86", "{. c #998A75", "]. c #9B8C76", "^. c #B3A288", "/. c #C2AF93", "(. c #C1AE93", "_. c #D6C1A4", ":. c #DEC8AA", "<. c #D2BDA0", "[. c #887B69", "}. c #5C554B", "|. c #6F6659", "1. c #B3A289", "2. c #A89880", "3. c #988974", "4. c #BEAB90", "5. c #C5B296", "6. c #B5A489", "7. c #C0AD91", "8. c #A2927C", "9. c #7F7362", "0. c #8D806C", "a. c #938570", "b. c #E0C9AA", "c. c #DAC4A6", "d. c #948570", "e. c #6F675B", "f. c #7E7364", "g. c #BAA78D", "h. c #B7A48B", "i. c #AB9A82", "j. c #AA9981", "k. c #AD9C83", "l. c #B4A187", "m. c #B6A289", "n. c #9E8D77", "o. c #857865", "p. c #847664", "q. c #AA9982", "r. c #A7977F", "s. c #D0BC9E", "t. c #E3CCAC", "u. c #DDC7A8", "v. c #A6957D", "w. c #776D5E", "x. c #887C6A", "y. c #C4B094", "z. c #D2BC9F", "A. c #CBB79A", "B. c #C3B094", "C. c #C4B095", "D. c #CBB69A", "E. c #C9B498", "F. c #B2A087", "G. c #A1917B", "H. c #C1AD93", "I. c #C9B598", "J. c #DCC6A7", "K. c #E4CEAD", "L. c #A1917A", "M. c #766C5C", "N. c #8B7E6B", "O. c #D5C0A1", "P. c #E5CEAE", "Q. c #E5CDAD", "R. c #E2CCAC", "S. c #E2CCAD", "T. c #E4CDAE", "U. c #E0C9AB", "V. c #D3BEA1", "W. c #E1CBAB", "X. c #D3BEA0", "Y. c #90826E", "Z. c #6C6355", "`. c #817664", " + c #DFC9A9", ".+ c #E2CBAC", "++ c #E4CDAD", "@+ c #756B5C", "#+ c #897D6A", "$+ c #B6A58B", "%+ c #E4CEAE", "&+ c #D5BFA2", "*+ c #B7A58C", "=+ c #928571", "-+ c #73695B", ";+ c #9E8F79", ">+ c #C3B095", ",+ c #DEC8A9", "'+ c #DBC5A7", ")+ c #CDB99C", "!+ c #B3A188", "~+ c #988A76", "{+ c #786E5F", "]+ c #867A6A", "^+ c #AE9E86", "/+ c #D1BD9F", "(+ c #E1CAAA", "_+ c #DFC8A8", ":+ c #E4CCAC", "<+ c #9A8C77", "[+ c #7B6F60", "}+ c #8F8370", "|+ c #A69880", "1+ c #D8C3A4", "2+ c #DEC8A8", "3+ c #E4CCAD", "4+ c #E5CDAE", "5+ c #E3CDAC", "6+ c #A5957F", "7+ c #6B6456", "8+ c #897D6B", "9+ c #CEBA9C", "0+ c #E2CBAB", "a+ c #90826F", "b+ c #585249", "c+ c #796F61", "d+ c #C6B297", "e+ c #E5CEAF", "f+ c #E3CDAD", "g+ c #E0CAAB", "h+ c #B09F88", "i+ c #908270", "j+ c #645D53", "k+ c #817768", "l+ c #C6B398", "m+ c #E3CEAE", "n+ c #E2CDAE", "o+ c #E1CBAD", "p+ c #BAA890", "q+ c #A0927D", " . + @ # $ % & * * ", " = - ; > , ' ) ! ~ ", "{ ] ^ / ( _ : < [ } | 1 2 3 4 5 ", "6 7 8 9 0 a b c d e f g h i j k l ", "m n o p q r s t u v w x y z j A B C ", "D E F G H I J K L M N H O P 3 Q R S T ", "U V W X 4 Y Z ` ...+.@.#.$.%.&.t x *.=.", "-.;.>.i ,.4 '.f ).!.~.{.].^./.(._.:.<.[.", "}.|.1.2.3.Q 4.5.6.7.j 8.9.0.3.a.v b.c.d.", "e.f.~.g.h.i.j.k.l.m.n.o.p.^ q.r.s.t.u.v.", "w.x.y.z.<.A.B.C.D.E.F.G.: H.b I.J.K.J.L.", "M.N.O.t.P.Q.R.S.T.U.V.'.u.t.P.P.P.W.X.Y.", "Z.`.A. +P.P.P.P.P.T.t..+++P.P.P.++s L @+", " #+$+V.%+P.P.P.P.P.P.P.P.P.P.++&+*+=+-+", " ;+>+,+P.++t.t.++P.P.P.R.'+)+!+~+{+ ", " ]+^+/+++(+_+_+t.:+t.P.u.>.<+[+m ", " }+|+1+2+b.b.3+4+++5+| 6+ ", " 7+8+9+J..+.+T.P.++0++.a+ ", " b+c+d+J.P.P.e+%+f+g+h+i+ ", " j+k+l+J.P.P.%+m+n+o+p+q+ "}; mdbtools-0.7.1/src/gmdb2/pixmaps/macros.xpm000066400000000000000000000045661222645741400206410ustar00rootroot00000000000000/* XPM */ static char * macros_xpm[] = { "14 14 120 2", " c None", ". c #564F44", "+ c #554C41", "@ c #534D44", "# c #817867", "$ c #756A5C", "% c #756B5E", "& c #70685C", "* c #A0907A", "= c #827766", "- c #998A75", "; c #C8B498", "> c #887A68", ", c #C5B195", "' c #887B68", ") c #A8977F", "! c #9A8A75", "~ c #6D6356", "{ c #DEC7A9", "] c #A0907B", "^ c #C4B196", "/ c #DDC7A8", "( c #A1917C", "_ c #CDB99C", ": c #D9C3A5", "< c #A2927C", "[ c #C5B296", "} c #7A7165", "| c #6E6456", "1 c #E1C9AB", "2 c #A89781", "3 c #BFAD93", "4 c #E1CAAB", "5 c #B6A48B", "6 c #D3BEA1", "7 c #B4A38A", "8 c #9B8C76", "9 c #9C8D76", "0 c #92836F", "a c #897C69", "b c #8A7C69", "c c #5F564B", "d c #AC9A83", "e c #E5CEAD", "f c #B3A188", "g c #CBB79A", "h c #877A67", "i c #B3A287", "j c #E0C9A9", "k c #E1CBAB", "l c #E2CBAD", "m c #D8C2A5", "n c #6B6255", "o c #595349", "p c #BDAB90", "q c #968772", "r c #8F806C", "s c #D6C1A3", "t c #B4A388", "u c #C5B295", "v c #B2A088", "w c #796D5D", "x c #978973", "y c #90826E", "z c #DCC6A8", "A c #E4CDAD", "B c #7D705F", "C c #756C5F", "D c #B6A48A", "E c #C5B196", "F c #B2A188", "G c #9E8F78", "H c #B3A087", "I c #B39F86", "J c #7A6E5D", "K c #867866", "L c #B09F87", "M c #AD9C83", "N c #E3CDAC", "O c #E5CEAE", "P c #9D8C76", "Q c #796E5E", "R c #E3CCAA", "S c #E5CDAD", "T c #E0CAAB", "U c #E4CDAE", "V c #DDC7A9", "W c #C0AD92", "X c #DEC8A9", "Y c #847764", "Z c #6B6254", "` c #D4BFA1", " . c #E3CCAD", ".. c #BFAC91", "+. c #5E574C", "@. c #A89880", "#. c #E3CDAD", "$. c #E3CCAC", "%. c #786E5F", "&. c #867A6A", "*. c #C9B699", "=. c #DEC7A7", "-. c #D7C2A4", ";. c #9A8C77", ">. c #797060", ",. c #D3BFA0", "'. c #E0C9AA", "). c #E5CDAE", "!. c #E2CCAB", "~. c #928470", "{. c #565148", "]. c #C6B297", "^. c #E5CEAF", "/. c #E4CEAE", "(. c #8E806E", "_. c #676056", ":. c #C6B398", "<. c #E2CDAE", "[. c #E1CBAD", "}. c #A49681", " . + @ # $ % ", "& * = - ; > , ; ' ) ! ", "~ { ] ^ / ( _ : < [ ; } ", "| 1 2 3 4 5 6 7 8 9 0 a b ", "c { 0 d e f g h i j k l m n ", "o p q r s t u v w x y z A B ", "C D E F G H I J K L M N O P ", "Q R O S T U V W X O O O A Y ", "Z ` O O O O O O O O O ...+.", " @.#.O O O O O O O $.W %. ", " &.*.A j =.A $.O -.;.~ ", " >.,.4 '.).O !.~. ", " {.].O O ^./.T (. ", " _.:.O O /.<.[.}. "}; mdbtools-0.7.1/src/gmdb2/pixmaps/module_big.xpm000066400000000000000000000012061222645741400214470ustar00rootroot00000000000000/* XPM */ static char * module_big_xpm[] = { "24 20 2 1", " c None", ". c #000000", " ", " ", " ", " . .. . . ", " . .. . . ", " . . . ", " . . . ", " .... .. ... .. ..", " . .. .. . ..", " . .. .. . ..", " . .. .. ..", " . .. .. ..", " . .. . .. ..", " . . . .. . ", " ... .. ... .... .. ", " . . ", " ", " ", " ", " "}; mdbtools-0.7.1/src/gmdb2/pixmaps/pk.xpm000066400000000000000000000006731222645741400177620ustar00rootroot00000000000000/* XPM */ static char * pk_xpm[] = { "16 16 5 1", " c None", ". c #FFBF00", "+ c #1C59DD", "@ c #000000", "# c #E8AC17", " ", " .... +++ ", " ..@@.. + + ", " ...... + + ", " ...... +++ ", " .... + ", " .# + ", " .# ", " .# + + ", " .#. + + ", " .#.. ++ ", " .# + + ", " .#. + + ", " .#.. + + ", " ", " "}; mdbtools-0.7.1/src/gmdb2/pixmaps/query.xpm000066400000000000000000000012551222645741400205120ustar00rootroot00000000000000/* XPM */ static char * query_xpm[] = { "10 12 31 1", " c None", ". c #C9C5C5", "+ c #C2BEBE", "@ c #D0CCCC", "# c #DAD5D5", "$ c #C1BDBD", "% c #9B9B9B", "& c #B6B5B5", "* c #C0BCBC", "= c #9D9C9C", "- c #D4D1D1", "; c #CCC8C8", "> c #8C8C8C", ", c #A09F9F", "' c #959696", ") c #A7A6A6", "! c #C6C1C1", "~ c #8D8E8E", "{ c #A4A5A5", "] c #BEBBBB", "^ c #C3C0C0", "/ c #9D9E9E", "( c #AFACAC", "_ c #949595", ": c #B9B7B7", "< c #AEABAB", "[ c #B0AEAE", "} c #A2A2A2", "| c #A5A5A5", "1 c #979797", "2 c #ACABAB", " .+@ ", " #$%&*%=- ", " ;> ,' ", " )> !~+", " +{ ]~+", " ^~/ ", " (_: ", " <[ ", " } ", " ", " |+ ", " +12 "}; mdbtools-0.7.1/src/gmdb2/pixmaps/query_big.xpm000066400000000000000000000012251222645741400213300ustar00rootroot00000000000000/* XPM */ static char * query_big_xpm[] = { "20 24 2 1", " c None", ". c #000000", " ", " ", " ........ ", " .. ..... ", " .... ..... ", " ..... ..... ", " ..... ..... ", " .... ..... ", " ..... ", " ..... ", " .... ", " .... ", " .. ", " .. ", " . ", " . ", " ", " ... ", " ..... ", " ..... ", " ..... ", " .... ", " ", " "}; mdbtools-0.7.1/src/gmdb2/pixmaps/report_big.xpm000066400000000000000000000077121222645741400215050ustar00rootroot00000000000000/* XPM */ static char * report_big_xpm[] = { "20 20 194 2", " c None", ". c #45372B", "+ c #746450", "@ c #766654", "# c #736250", "$ c #625241", "% c #5E4844", "& c #D9C3A0", "* c #EAD7B7", "= c #E0CAAB", "- c #9C8A71", "; c #171512", "> c #15120E", ", c #5F4946", "' c #DFCAAB", ") c #EFE2CD", "! c #F0E6D7", "~ c #E8DBC9", "{ c #D1BEA2", "] c #BBA382", "^ c #3F362B", "/ c #020201", "( c #000000", "_ c #5D4D43", ": c #DFD1BF", "< c #F5EDE2", "[ c #FAF5EE", "} c #FBF5EE", "| c #F8EFE4", "1 c #F0E3D3", "2 c #BCAE9A", "3 c #9B8A72", "4 c #826F5B", "5 c #564642", "6 c #594A46", "7 c #605346", "8 c #E0D6C9", "9 c #F8F2EA", "0 c #FDF9F5", "a c #FEFBF8", "b c #FEFAF7", "c c #FDF6F0", "d c #F6EADB", "e c #C3B19E", "f c #7E6A5B", "g c #4C3E3C", "h c #584946", "i c #2A2221", "j c #65584A", "k c #E4DACC", "l c #F9F3EA", "m c #FDF8F3", "n c #FEFAF5", "o c #FDF8F5", "p c #FBF4EE", "q c #FBF3EC", "r c #AA9E99", "s c #554643", "t c #4E413D", "u c #806F62", "v c #28231F", "w c #6E5E4F", "x c #E8DECF", "y c #FCF5EA", "z c #FEF8EF", "A c #FEF7EF", "B c #FCF6F0", "C c #F9F1E7", "D c #FAF1E6", "E c #A69A93", "F c #514240", "G c #5E4F49", "H c #CAB695", "I c #453F33", "J c #624E3D", "K c #A88A70", "L c #F1E6D6", "M c #FDF4E7", "N c #FEF5EA", "O c #FCF4E8", "P c #F9F0E3", "Q c #F7EEDE", "R c #F7EDDD", "S c #807A72", "T c #090707", "U c #0A0908", "V c #161411", "W c #4B3B2E", "X c #766554", "Y c #DECAB1", "Z c #F8ECD7", "` c #FDF2DF", " . c #FEF3E0", ".. c #FCF1DE", "+. c #F8EBD7", "@. c #F5E8D3", "#. c #F2E2CE", "$. c #7A7167", "%. c #030202", "&. c #493A2E", "*. c #7C6D5C", "=. c #F4E4C9", "-. c #F9EAD0", ";. c #FCEED4", ">. c #F5E5CA", ",. c #EFDFC6", "'. c #EAD8BE", "). c #756C5E", "!. c #5D4D3C", "~. c #8E7D67", "{. c #F0DEBE", "]. c #F1DFBE", "^. c #F6E5C5", "/. c #F5E4C5", "(. c #F2E0C2", "_. c #F0DDBF", ":. c #E9D7BA", "<. c #E2CDAF", "[. c #6F6555", "}. c #584B40", "|. c #584A3E", "1. c #564739", "2. c #7F6B55", "3. c #B8A080", "4. c #DBC5A0", "5. c #E0C8A1", "6. c #E9D1AE", "7. c #EBD5B3", "8. c #EAD5B4", "9. c #EAD5B6", "0. c #E6D1B2", "a. c #CCB696", "b. c #665A48", "c. c #7B7067", "d. c #ECE8E5", "e. c #ECE5D8", "f. c #DAC6AA", "g. c #AB9177", "h. c #866C58", "i. c #907560", "j. c #BDA381", "k. c #D3B995", "l. c #DBC19E", "m. c #DEC5A1", "n. c #E2C8A4", "o. c #DAC09D", "p. c #514839", "q. c #15130E", "r. c #726252", "s. c #DECAB0", "t. c #EFDEC5", "u. c #F5E9D9", "v. c #E8DCCE", "w. c #D3C1AD", "x. c #BFA486", "y. c #9A7F66", "z. c #997E66", "A. c #AE9477", "B. c #C5AB88", "C. c #C9AF8C", "D. c #C7AC89", "E. c #3C3429", "F. c #010100", "G. c #544637", "H. c #685A48", "I. c #746A5A", "J. c #C4B6A5", "K. c #EDDFCA", "L. c #F4E6D0", "M. c #EBDCCA", "N. c #C5B4A3", "O. c #B69E86", "P. c #9D856F", "Q. c #8A7663", "R. c #927C67", "S. c #B29A7A", "T. c #372F25", "U. c #6E5F4B", "V. c #9A8972", "W. c #BBAE9C", "X. c #F1E6DA", "Y. c #F7EDDA", "Z. c #CCB8A0", "`. c #867364", " + c #5F4E48", ".+ c #776651", "++ c #2E281F", "@+ c #3C3329", "#+ c #7E6E64", "$+ c #4F413E", "%+ c #463A37", "&+ c #594946", "*+ c #181413", "=+ c #1B1615", " . . . . ", " + @ # $ ", " % & * = - ; > ", " , ' ) ! ~ { ] ^ / ( ", " _ : < [ } | 1 2 3 4 5 6 ", " 7 8 9 0 a b c d e f g h i ", " j k l m n o p q r s t u v ", " w x y z A B C D E F G H I ", " J K L M N O P Q R S T U V ", " W X Y Z ` ...+.@.#.$.%. ", " &.*.=.-.;.;.-.>.,.'.)./ ", " !.~.{.].^./.(._.:.<.[.( ", " }.|.1.2.3.4.5.6.7.8.9.0.a.b.( ", ". c.d.e.f.g.h.i.j.k.l.m.n.o.p.q. ", ". r.s.t.u.v.w.x.y.z.A.B.C.D.E.F. ", ". G.H.I.J.K.L.M.N.O.P.Q.R.S.T.( ", " ( ( U.V.W.X.Y.Z.`.s +.+++ ", " ( ( @+] { #+$+$+G U ", " > ; %+&+u H V ", " *+=+v I "}; mdbtools-0.7.1/src/gmdb2/pixmaps/reports.xpm000066400000000000000000000027521222645741400210460ustar00rootroot00000000000000/* XPM */ static char * reports_xpm[] = { "16 16 76 1", " c None", ". c #45372B", "+ c #4F3939", "@ c #E7D1AA", "# c #EBD7B9", "$ c #D1B692", "% c #000000", "& c #F0DBB9", "* c #F0E7D9", "= c #F5EBDF", "- c #CDB18C", "; c #050403", "> c #4C3E31", ", c #EFE4D7", "' c #FBF7F3", ") c #FFFCF9", "! c #FDF6EF", "~ c #554542", "{ c #5A4A47", "] c #55473A", "^ c #F2E9DB", "/ c #FBF6F0", "( c #FEFBF8", "_ c #FEFAF7", ": c #FCF4EF", "< c #FAF3ED", "[ c #413533", "} c #57483A", "| c #F7EDDE", "1 c #FEF8F0", "2 c #FEF8EF", "3 c #FDF7F3", "4 c #F9F1E7", "5 c #FBF2E7", "6 c #594946", "7 c #EFD8B0", "8 c #A78568", "9 c #FBF2E3", "0 c #FEF5E8", "a c #FDF5EA", "b c #F9EFE2", "c c #F7EDDC", "d c #F7ECDC", "e c #4D3D30", "f c #F1E2CA", "g c #FCEFD9", "h c #FEF2DC", "i c #F8EAD3", "j c #F4E5CE", "k c #EEDBC5", "l c #F5E5C7", "m c #F7E7C9", "n c #FCEED0", "o c #F6E6C8", "p c #F4E1C3", "q c #E9D8BC", "r c #E2CFB1", "s c #AE9676", "t c #E5CFA8", "u c #E4CCA5", "v c #EFD8B6", "w c #EBD7B5", "x c #E7D3B4", "y c #D7BD99", "z c #FFFCFB", "A c #FFF8E9", "B c #E2C7A3", "C c #806553", "D c #BFA582", "E c #DBC19D", "F c #020200", "G c #E1C6A2", "H c #836854", "I c #B89F7D", "J c #FEF7E8", "K c #5D4B47", " ... ", " +@#$%% ", " +&*=#-;% ", " >,'))!#-~{ ", " ]^/(_:<{[{%", " }|12345{67%", " .890abcd%%% ", " efghhijk; ", " .lmnopqr% ", " ...stuvw#xy% ", ".zABCCDyEByF ", ".-#zAGHCIDD% ", " %%-#zJB{Ks% ", " %%-#{[{% ", " %%{{7% ", " %%% "}; mdbtools-0.7.1/src/gmdb2/pixmaps/stock_export-16.png000066400000000000000000000012061222645741400222710ustar00rootroot00000000000000‰PNG  IHDRó˙abKGD˙˙˙ ˝§“;IDATxÚť“ĎKTQÇ?óÇy)ůkÔ|ڶpD¤Vµ­ j“…P@«˘hÓ"µ”0‚ĚM%AŃÎ…-‹6&˘CY á=)LeŢsľ7ăĚ8ľw[TŁĎ‘8p.÷|Ďý~ď÷^€.@üg^ň"›Ű"ús{bąÜËî8złŻXÜ˝ÍŔŕ}׾`ŮČ2ýiŰAhË „«éĺó12›LÓddxLÚ˘ŕÁ΀t~€–ó— ‡ĂE $I¨K*ş®Ł.Ĺh·Ôîô°'TU-&ŔŤë×µ„Đ× UV× µrˇű@Ě'Ö™üđ™łG‚ű2čë˝Ĺą‚@CEQĚNsočᎄ˝ ţF4Ąłł“Úšâń8ć†Áě̙ͬ #ćëâŃř¤HĄRÂqá8Ž0MShšć˛íĚé%Vş$´6VÓÜT‡ť/ŰŢvťręXG±{ĹűČ o^ڏ%Ä“|[5ŘL›%·{çéÂxˤŇwPÔ"ˇJJ¨ Y–Q]×™ŤDx<ţ–î“Çńďoc.—C ř¸xµź+˝ĂhšF*•Binfyu…Ż«i+ĄŇůB{+€ßď§±ľ–p¸Ă0đů|8…xď 2ëŮží<˙óň;Ďsžsžż‹˙/bZŰý`§ö\ ܉ë ŔnúöĽŘq;Ń·x:`3 ţĄŢÚľ}{°¦ćý ĐV^VęřŁŹň˛RĐvčŕľ 0t.W .uGÔ'ik8ÎÎMĄhn7JJ¤®ć†¸]°áuľ»ŘÄŘŘ(áĐPŇ­ÉÉ |>?áĐ —Ż\ٱ©9Ěő$*B˙o}Ś Ź1yůD'@‚cYŕ c1¬@źoÝÄš’µ?q€¦ ńĄ¸yşđ&ĆŃc1›šŢĽI€R.¤ř}~BŰN©ŔĺĹe+”7Ť•{ް®¬€––†‡GŕĆŤŞ«+iożFyY)ŤMÍő@JŕH‰ňHŇ‚nVíŢ?ăéş|Ƨꤰp áЦ%číýťpxŚ9¬[ż‘ţľ^ŚEŹńî;oĺŐź:3ŞMĎ/iʇ¦Pí®Ý;z €ĺË—‘“ťEz0ťwěŔ4 CÜľ=@ý©3Ł€ôLMU(uŻŐŃŃJÓ¤µµ•îîn*++©Ş®˘żŻ—˝űö°Ľč9ĆÇFůú«ł‰3Ř|źĚ˘oş†hm˙™ţK ÔŐŐÍęAFFgNŤDDîŇß× €‹0fdřO›šŁ@nŇiH„&ÉĚĚ|hö8Ěă ůňÜyJ^^ĹŇĄ…tuÝŕâ—Y[úbÂ’S)Ĺ?†ŕôéÓlٲ…ÎÎNNž×,gpýÇ xńu$¶eÓut]G8"™5¦cnV69ąyř|~LÓ@JeZxĄBJ…bFŔĘăű?şşćµ­3łČ_Ľ„kmWČĎĎç˝ę*˛ç/ -=`pŹ—‰ńQ~˝Ůi¤ăFX–&QÉ€ˇ˝đuyF}޸$Ń®Î/ ©qőNűţ¨˘âQ ör ]nŻ(IEND®B`‚mdbtools-0.7.1/src/gmdb2/pixmaps/table.xpm000066400000000000000000000004271222645741400204340ustar00rootroot00000000000000/* XPM */ static char * table_xpm[] = { "10 12 4 1", " c None", ". c #1874B1", "+ c #606060", "@ c #D7D2D2", "..........", "..........", "+@@+@@@+@+", "++++++++++", "+@@+@@@+@+", "++++++++++", "+@@+@@@+@+", "++++++++++", "+@@+@@@+@+", "++++++++++", "+@@+@@@+@+", "++++++++++"}; mdbtools-0.7.1/src/gmdb2/pixmaps/table_big.xpm000066400000000000000000000013761222645741400212610ustar00rootroot00000000000000/* XPM */ static char * table_big_xpm[] = { "20 24 9 1", " c None", ". c #1874B1", "+ c #3C6A88", "@ c #5A86A5", "# c #78A3C2", "$ c #606060", "% c #9C9999", "& c #D7D2D2", "* c #7E7C7C", "....................", "....................", "....................", "....................", "++@###@+@#####@+@#@+", "$$%&&&%$%&&&&&%$%&%$", "$$*%%%*$*%%%%%*$*%*$", "$$$$$$$$$$$$$$$$$$$$", "$$*%%%*$*%%%%%*$*%*$", "$$%&&&%$%&&&&&%$%&%$", "$$*%%%*$*%%%%%*$*%*$", "$$$$$$$$$$$$$$$$$$$$", "$$*%%%*$*%%%%%*$*%*$", "$$%&&&%$%&&&&&%$%&%$", "$$*%%%*$*%%%%%*$*%*$", "$$$$$$$$$$$$$$$$$$$$", "$$*%%%*$*%%%%%*$*%*$", "$$%&&&%$%&&&&&%$%&%$", "$$*%%%*$*%%%%%*$*%*$", "$$$$$$$$$$$$$$$$$$$$", "$$*%%%*$*%%%%%*$*%*$", "$$%&&&%$%&&&&&%$%&%$", "$$*%%%*$*%%%%%*$*%*$", "$$$$$$$$$$$$$$$$$$$$"}; mdbtools-0.7.1/src/gmdb2/prefs.c000066400000000000000000000061151222645741400164210ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * 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. */ #include #include #include "gmdb.h" extern GtkWidget *app; extern MdbHandle *mdb; GladeXML *prefswin_xml; unsigned long gmdb_prefs_get_maxrows() { gchar *str; str = gnome_config_get_string("/gmdb/prefs/maxrows"); if (!str || !strlen(str)) return 1000; else return atol(str); } /* callbacks */ static void gmdb_prefs_help_cb(GtkWidget *w, gpointer data) { GError *error = NULL; gnome_help_display("gmdb.xml", "gmdb-prefs", &error); if (error != NULL) { g_warning ("%s", error->message); g_error_free (error); } } static void gmdb_prefs_save_cb(GtkWidget *w, GladeXML *xml) { GtkWidget *entry; GtkWidget *win; gchar *str; entry = glade_xml_get_widget (xml, "maxrows_entry"); str = (gchar *) gtk_entry_get_text(GTK_ENTRY(entry)); printf("str = %s\n",str); gnome_config_set_string("/gmdb/prefs/maxrows", str); gnome_config_sync(); win = glade_xml_get_widget (xml, "prefs_dialog"); if (win) gtk_widget_destroy(win); } static void gmdb_prefs_cancel_cb(GtkWidget *w, GladeXML *xml) { GtkWidget *win; win = glade_xml_get_widget (xml, "prefs_dialog"); if (win) gtk_widget_destroy(win); } GtkWidget * gmdb_prefs_new() { GtkWidget *prefswin, *button; GtkWidget *entry; gchar *str; /* load the interface */ prefswin_xml = glade_xml_new(GMDB_GLADEDIR "gmdb-prefs.glade", NULL, NULL); /* connect the signals in the interface */ glade_xml_signal_autoconnect(prefswin_xml); entry = glade_xml_get_widget (prefswin_xml, "maxrows_entry"); button = glade_xml_get_widget (prefswin_xml, "cancel_button"); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (gmdb_prefs_cancel_cb), prefswin_xml); button = glade_xml_get_widget (prefswin_xml, "ok_button"); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (gmdb_prefs_save_cb), prefswin_xml); button = glade_xml_get_widget (prefswin_xml, "help_button"); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (gmdb_prefs_help_cb), prefswin_xml); str = gnome_config_get_string("/gmdb/prefs/maxrows"); if (!str || !strlen(str)) { str = "1000"; gnome_config_set_string("/gmdb/prefs/maxrows", str); gnome_config_sync(); } gtk_entry_set_text(GTK_ENTRY(entry), str); prefswin = glade_xml_get_widget (prefswin_xml, "prefs_dialog"); return prefswin; } mdbtools-0.7.1/src/gmdb2/schema.c000066400000000000000000000161221222645741400165410ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * 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. */ #include #include #include #include "gmdb.h" extern GtkWidget *app; extern MdbHandle *mdb; GladeXML *schemawin_xml; static gchar backend[100]; static gchar tabname[MDB_MAX_OBJ_NAME+1]; static guint32 export_options; #define ALL_TABLES "(All Tables)" static struct { const char *option_name; guint32 option_value; } capabilities_xlt[] = { { "drop_checkbox", MDB_SHEXP_DROPTABLE }, { "cstnotnull_checkbox", MDB_SHEXP_CST_NOTNULL }, { "cstnotempty_checkbox", MDB_SHEXP_CST_NOTEMPTY}, { "comments_checkbox", MDB_SHEXP_COMMENTS}, { "defaults_checkbox", MDB_SHEXP_DEFVALUES }, { "index_checkbox", MDB_SHEXP_INDEXES}, { "rel_checkbox", MDB_SHEXP_RELATIONS} }; #define n_capabilities (sizeof(capabilities_xlt)/sizeof(capabilities_xlt[0])) static void gmdb_schema_export(const gchar *file_path) { FILE *outfile; GtkWidget *dlg; //printf("file path %s\n",file_path); if ((outfile=fopen(file_path, "w"))==NULL) { GtkWidget* dlg = gtk_message_dialog_new (NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, _("Unable to open file.")); gtk_dialog_run (GTK_DIALOG (dlg)); gtk_widget_destroy (dlg); return; } mdb_set_default_backend(mdb,backend); mdb_print_schema(mdb, outfile, *tabname?tabname:NULL, NULL, export_options); fclose(outfile); dlg = gtk_message_dialog_new (NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, _("Schema exported successfully.")); gtk_dialog_run (GTK_DIALOG (dlg)); gtk_widget_destroy (dlg); } void gmdb_schema_export_cb(GtkWidget *w, gpointer data) { GtkWidget *schemawin, *checkbox, *chooser; GtkComboBox *combobox; const gchar *file_path; gchar *tmp; int i; schemawin = glade_xml_get_widget (schemawin_xml, "schema_dialog"); chooser = glade_xml_get_widget (schemawin_xml, "filename_entry"); file_path = gtk_entry_get_text(GTK_ENTRY(chooser)); combobox = GTK_COMBO_BOX(glade_xml_get_widget(schemawin_xml, "table_combo")); tmp = gtk_combo_box_get_active_text(combobox); strncpy(tabname,tmp,MDB_MAX_OBJ_NAME); tabname[MDB_MAX_OBJ_NAME]=0; if (!strcmp(tabname,ALL_TABLES)) tabname[0]='\0'; combobox = GTK_COMBO_BOX(glade_xml_get_widget (schemawin_xml, "backend_combo")); tmp = gtk_combo_box_get_active_text(combobox); if (!strcmp(tmp, "Oracle")) strcpy(backend, "oracle"); else if (!strcmp(tmp, "Sybase")) strcpy(backend,"sybase"); else if (!strcmp(tmp,"MS SQL Server")) strcpy(backend,"sybase"); else if (!strcmp(tmp, "PostgreSQL")) strcpy(backend,"postgres"); else if (!strcmp(tmp,"MySQL")) strcpy(backend,"mysql"); else if (!strcmp(tmp,"SQLite")) strcpy(backend,"sqlite"); else strcpy(backend,"access"); /* make sure unknown default options are enabled */ export_options = MDB_SHEXP_DEFAULT; for (i=0; icapabilities; //printf("backend capabilities: 0x%04x\n", capabilities); for (i=0; imessage); g_error_free (error); } } void gmdb_schema_new_cb(GtkWidget *w, gpointer data) { GtkComboBox *combobox; MdbCatalogEntry *entry; int i; /* load the interface */ schemawin_xml = glade_xml_new(GMDB_GLADEDIR "gmdb-schema.glade", NULL, NULL); /* connect the signals in the interface */ glade_xml_signal_autoconnect(schemawin_xml); /* set up capabilities call back. TODO: autoconnect should do that */ combobox = GTK_COMBO_BOX(glade_xml_get_widget(schemawin_xml, "backend_combo")); gtk_combo_box_set_active(combobox, 0); g_signal_connect( G_OBJECT (combobox), "changed", G_CALLBACK(gmdb_schema_backend_cb), NULL); /* set signals with user data, anyone know how to do this in glade? */ combobox = GTK_COMBO_BOX(glade_xml_get_widget(schemawin_xml, "table_combo")); gtk_combo_box_append_text(combobox, ALL_TABLES); /* add all user tables in catalog to list */ for (i=0; i < mdb->num_catalog; i++) { entry = g_ptr_array_index (mdb->catalog, i); if (mdb_is_user_table(entry)) { gtk_combo_box_append_text(combobox, entry->object_name); } } /* for */ gtk_combo_box_set_active(combobox, 0); check_default_options(); refresh_available_options(); } mdbtools-0.7.1/src/gmdb2/sql.c000066400000000000000000000547051222645741400161110ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * 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. */ #include #include #include "gmdb.h" #if SQL GList *sql_list; extern MdbHandle *mdb; extern MdbSQL *sql; static void gmdb_sql_tree_populate (MdbHandle*, GladeXML*); static void gmdb_sql_load_query (GladeXML*, gchar*); static void gmdb_sql_save_query (GladeXML*, gchar*); static void gmdb_sql_save_as_cb (GtkWidget*, GladeXML*); void gmdb_sql_close_all() { GladeXML *xml; GtkWidget *win; while ((xml = g_list_nth_data(sql_list, 0))) { win = glade_xml_get_widget (xml, "sql_window"); sql_list = g_list_remove(sql_list, xml); if (win) gtk_widget_destroy(win); } } gchar* gmdb_export_get_filepath (GladeXML*); /* from table_export.c */ /* callbacks */ static void gmdb_sql_write_rslt_cb(GtkWidget *w, GladeXML *xml) { /* We need to re-run the whole query because some information is not stored * in the TreeStore, such as column types. */ gchar *file_path; GladeXML *sql_xml; GtkWidget *filesel, *dlg; FILE *outfile; int i; int need_headers = 0; gchar delimiter[11]; gchar quotechar[5]; gchar escape_char[5]; int bin_mode; gchar lineterm[5]; guint len; gchar *buf; GtkTextIter start, end; GtkTextBuffer *txtbuffer; GtkWidget *textview; char **bound_values; int *bound_lens; MdbSQLColumn *sqlcol; long row; char *value; size_t length; MdbTableDef *table; MdbColumn *col = NULL; gmdb_export_get_delimiter(xml, delimiter, sizeof(delimiter)); gmdb_export_get_lineterm(xml, lineterm, sizeof(lineterm)); gmdb_export_get_quotechar(xml, quotechar, sizeof(quotechar)); gmdb_export_get_escapechar(xml, escape_char, sizeof(escape_char)); bin_mode = gmdb_export_get_binmode(xml); need_headers = gmdb_export_get_headers(xml); file_path = gmdb_export_get_filepath(xml); if ((outfile=fopen(file_path, "w"))==NULL) { dlg = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (w)), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, _("Unable to open file.")); gtk_dialog_run (GTK_DIALOG (dlg)); gtk_widget_destroy (dlg); return; } /* Get SQL */ filesel = glade_xml_get_widget (xml, "export_dialog"); sql_xml = g_object_get_data(G_OBJECT(filesel), "sql_xml"); //printf("sql_xml %p\n",sql_xml); textview = glade_xml_get_widget(sql_xml, "sql_textview"); txtbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview)); len = gtk_text_buffer_get_char_count(txtbuffer); gtk_text_buffer_get_iter_at_offset (txtbuffer, &start, 0); gtk_text_buffer_get_iter_at_offset (txtbuffer, &end, len); buf = gtk_text_buffer_get_text(txtbuffer, &start, &end, FALSE); /* ok now execute it */ mdb_sql_run_query(sql, buf); if (mdb_sql_has_error(sql)) { GtkWidget* dlg = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (w)), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, "%s", mdb_sql_last_error(sql)); gtk_dialog_run (GTK_DIALOG (dlg)); gtk_widget_destroy (dlg); mdb_sql_reset(sql); fclose(outfile); gtk_widget_destroy(filesel); return; } bound_values = (char **) g_malloc(sql->num_columns * sizeof(char *)); bound_lens = (int *) g_malloc(sql->num_columns * sizeof(int)); for (i=0; inum_columns; i++) { /* bind columns */ bound_values[i] = (char *) g_malloc0(MDB_BIND_SIZE); mdb_sql_bind_column(sql, i+1, bound_values[i], &bound_lens[i]); /* display column titles */ if (need_headers) { if (i>0) fputs(delimiter, outfile); sqlcol = g_ptr_array_index(sql->columns,i); gmdb_print_col(outfile, sqlcol->name, quotechar[0]!='\0', MDB_TEXT, 0, quotechar, escape_char, bin_mode); } } row = 0; while (mdb_fetch_row(sql->cur_table)) { row++; for (i=0; inum_columns; i++) { if (i>0) fputs(delimiter, outfile); sqlcol = g_ptr_array_index(sql->columns, i); /* Find col matching sqlcol */ table = sql->cur_table; for (i=0; inum_cols; i++) { col = g_ptr_array_index(table->columns, i); if (!strcasecmp(sqlcol->name, col->name)) break; } /* assert(i!=table->num_cols). Can't happen, already checked. */ /* Don't quote NULLs */ if (bound_lens[i] && sqlcol->bind_type != MDB_OLE) { if (col->col_type == MDB_OLE) { value = mdb_ole_read_full(mdb, col, &length); } else { value = bound_values[i]; length = bound_lens[i]; } gmdb_print_col(outfile, value, quotechar[0]!='\0', col->col_type, length, quotechar, escape_char, bin_mode); if (col->col_type == MDB_OLE) free(value); } } fputs(lineterm, outfile); } /* free the memory used to bind */ for (i=0; inum_columns; i++) { g_free(bound_values[i]); } mdb_sql_reset(sql); g_free(buf); fclose(outfile); dlg = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (w)), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, _("%ld rows successfully exported."), row); gtk_dialog_run (GTK_DIALOG (dlg)); gtk_widget_destroy (dlg); gtk_widget_destroy(filesel); } static void gmdb_sql_results_cb(GtkWidget *w, GladeXML *xml) { GladeXML *dialog_xml; GtkWidget *but; GtkWidget *filesel; /* load the interface */ dialog_xml = glade_xml_new(GMDB_GLADEDIR "gmdb-export.glade", NULL, NULL); /* connect the signals in the interface */ glade_xml_signal_autoconnect(dialog_xml); filesel = glade_xml_get_widget (dialog_xml, "export_dialog"); gtk_window_set_title(GTK_WINDOW(filesel), "Save Results As"); but = glade_xml_get_widget (dialog_xml, "export_button"); gtk_widget_hide(but); but = glade_xml_get_widget (dialog_xml, "save_button"); gtk_widget_show(but); gmdb_table_export_populate_dialog(dialog_xml); but = glade_xml_get_widget (dialog_xml, "save_button"); g_signal_connect (G_OBJECT (but), "clicked", G_CALLBACK (gmdb_sql_write_rslt_cb), dialog_xml); g_object_set_data(G_OBJECT(filesel), "sql_xml", xml); } static void gmdb_sql_save_cb(GtkWidget *w, GladeXML *xml) { GtkWidget *textview; gchar *str; textview = glade_xml_get_widget (xml, "sql_textview"); str = g_object_get_data(G_OBJECT(textview), "file_name"); if (!str) { gmdb_sql_save_as_cb(w, xml); return; } gmdb_sql_save_query(xml, str); } static void gmdb_sql_save_as_cb(GtkWidget *w, GladeXML *xml) { GtkWindow *parent_window = (GtkWindow *) glade_xml_get_widget (xml, "gmdb"); GtkWidget *dialog = gtk_file_chooser_dialog_new ("Save Query As", parent_window, GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) { char *filename; filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); gmdb_sql_save_query(xml, filename); } gtk_widget_destroy (dialog); } static void gmdb_sql_open_cb(GtkWidget *w, GladeXML *xml) { GtkWindow *parent_window = (GtkWindow *) glade_xml_get_widget (xml, "gmdb"); GtkWidget *dialog = gtk_file_chooser_dialog_new ("Open SQL Query", parent_window, GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) { char *filename; filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); gmdb_sql_load_query(xml, filename); } gtk_widget_destroy (dialog); } static void gmdb_sql_copy_cb(GtkWidget *w, GladeXML *xml) { GtkTextBuffer *txtbuffer; GtkClipboard *clipboard; GtkWidget *textview; textview = glade_xml_get_widget(xml, "sql_textview"); clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); txtbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview)); gtk_text_buffer_copy_clipboard(txtbuffer, clipboard); } static void gmdb_sql_cut_cb(GtkWidget *w, GladeXML *xml) { GtkTextBuffer *txtbuffer; GtkClipboard *clipboard; GtkWidget *textview; textview = glade_xml_get_widget(xml, "sql_textview"); clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); txtbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview)); gtk_text_buffer_cut_clipboard(txtbuffer, clipboard, TRUE); } static void gmdb_sql_paste_cb(GtkWidget *w, GladeXML *xml) { GtkTextBuffer *txtbuffer; GtkClipboard *clipboard; GtkWidget *textview; textview = glade_xml_get_widget(xml, "sql_textview"); clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); txtbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview)); gtk_text_buffer_paste_clipboard(txtbuffer, clipboard, NULL, TRUE); } static void gmdb_sql_close_cb(GtkWidget *w, GladeXML *xml) { GtkWidget *win; sql_list = g_list_remove(sql_list, xml); win = glade_xml_get_widget (xml, "sql_window"); if (win) gtk_widget_destroy(win); } static void gmdb_sql_dnd_dataget_cb( GtkWidget *w, GdkDragContext *dc, GtkSelectionData *selection_data, guint info, guint t, GladeXML *xml) { gchar tablename[256]; //gchar *tablename = "Orders"; gchar *name; GtkTreeSelection *select; GtkTreeStore *store; GtkTreeView *tree; GtkTreeIter iter2; tree = (GtkTreeView *) glade_xml_get_widget(xml, "sql_treeview"); select = gtk_tree_view_get_selection(GTK_TREE_VIEW (tree)); store = (GtkTreeStore *) gtk_tree_view_get_model(tree); gtk_tree_selection_get_selected (select, NULL, &iter2); gtk_tree_model_get (GTK_TREE_MODEL(store), &iter2, 0, &name, -1); strcpy(tablename,name); g_free(name); //strcpy(tablename, "Shippers"); gtk_selection_data_set( selection_data, GDK_SELECTION_TYPE_STRING, 8, /* 8 bits per character. */ (guchar*)tablename, strlen(tablename)); } static void gmdb_sql_dnd_datareceived_cb( GtkWidget *w, GdkDragContext *dc, gint x, gint y, GtkSelectionData *selection_data, guint info, guint t, GladeXML *xml) { GtkTextIter iter; GtkTextBuffer *txtbuffer; GtkWidget *textview; textview = glade_xml_get_widget(xml, "sql_textview"); txtbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview)); if (gtk_text_buffer_get_char_count(txtbuffer)==0) { gtk_text_buffer_get_iter_at_offset (txtbuffer, &iter, 0); gtk_text_buffer_insert(txtbuffer, &iter, "select * from ", 14); } gtk_widget_grab_focus(GTK_WIDGET(textview)); } static void gmdb_sql_select_hist_cb(GtkComboBox *combobox, GladeXML *xml) { gchar *buf; GtkTextBuffer *txtbuffer; GtkWidget *textview; buf = gtk_combo_box_get_active_text(combobox); if (!buf) return; textview = glade_xml_get_widget(xml, "sql_textview"); txtbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview)); gtk_text_buffer_set_text(txtbuffer, buf, strlen(buf)); } static void gmdb_sql_execute_cb(GtkWidget *w, GladeXML *xml) { guint len; gchar *buf; gchar *bound_data[256]; int i; MdbSQLColumn *sqlcol; GtkTextBuffer *txtbuffer; GtkTextIter start, end; GtkWidget *textview, *combobox, *treeview; GtkTreeModel *store; /*GtkWidget *window;*/ GType *gtypes; GtkTreeIter iter; GtkTreeViewColumn *column; long row, maxrow; /* GdkCursor *watch, *pointer; */ /* need to figure out how to clock during the treeview recalc/redraw window = glade_xml_get_widget(xml, "sql_window"); watch = gdk_cursor_new(GDK_WATCH); gdk_window_set_cursor(GTK_WIDGET(window)->window, watch); gdk_cursor_unref(watch); */ /* stuff this query on the history */ textview = glade_xml_get_widget(xml, "sql_textview"); combobox = glade_xml_get_widget(xml, "sql_combo"); txtbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview)); len = gtk_text_buffer_get_char_count(txtbuffer); gtk_text_buffer_get_iter_at_offset (txtbuffer, &start, 0); gtk_text_buffer_get_iter_at_offset (txtbuffer, &end, len); buf = gtk_text_buffer_get_text(txtbuffer, &start, &end, FALSE); /* add to the history */ gtk_combo_box_prepend_text(GTK_COMBO_BOX(combobox), buf); gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), 0); /* ok now execute it */ mdb_sql_run_query(sql, buf); if (mdb_sql_has_error(sql)) { GtkWidget* dlg = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (w)), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, "%s", mdb_sql_last_error(sql)); gtk_dialog_run (GTK_DIALOG (dlg)); gtk_widget_destroy (dlg); mdb_sql_reset(sql); return; } treeview = glade_xml_get_widget(xml, "sql_results"); gtypes = g_malloc(sizeof(GType) * sql->num_columns); for (i=0;inum_columns;i++) gtypes[i]=G_TYPE_STRING; store = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview)); if (store) { while ((column = gtk_tree_view_get_column(GTK_TREE_VIEW(treeview), 0))) { gtk_tree_view_remove_column(GTK_TREE_VIEW(treeview), column); } g_object_unref(store); } store = (GtkTreeModel*)gtk_list_store_newv(sql->num_columns, gtypes); g_free(gtypes); gtk_tree_view_set_model(GTK_TREE_VIEW(treeview), store); GtkCellRenderer *renderer; renderer = gtk_cell_renderer_text_new(); for (i=0;inum_columns;i++) { bound_data[i] = (char *) g_malloc0(MDB_BIND_SIZE); mdb_sql_bind_column(sql, i+1, bound_data[i], NULL); sqlcol = g_ptr_array_index(sql->columns,i); column = gtk_tree_view_column_new_with_attributes(sqlcol->name, renderer, "text", i, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW (treeview), column); } maxrow = gmdb_prefs_get_maxrows(); row = 0; while(mdb_fetch_row(sql->cur_table) && (!maxrow || (row < maxrow))) { row++; gtk_list_store_append(GTK_LIST_STORE(store), &iter); for (i=0;inum_columns;i++) { gtk_list_store_set(GTK_LIST_STORE(store), &iter, i, (gchar *) bound_data[i], -1); } } /* free the memory used to bind */ for (i=0;inum_columns;i++) { g_free(bound_data[i]); } mdb_sql_reset(sql); g_free(buf); /* pointer = gdk_cursor_new(GDK_LEFT_PTR); gdk_window_set_cursor(GTK_WIDGET(window)->window, pointer); gdk_cursor_unref(pointer); */ } void gmdb_sql_new_cb (GtkWidget *w, gpointer data) { GtkTargetEntry src; GtkWidget *mi, *but, *combobox; GladeXML *sqlwin_xml; /* load the interface */ sqlwin_xml = glade_xml_new(GMDB_GLADEDIR "gmdb-sql.glade", NULL, NULL); /* connect the signals in the interface */ glade_xml_signal_autoconnect(sqlwin_xml); sql_list = g_list_append(sql_list, sqlwin_xml); mi = glade_xml_get_widget (sqlwin_xml, "save_menu"); g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (gmdb_sql_save_cb), sqlwin_xml); but = glade_xml_get_widget (sqlwin_xml, "save_button"); g_signal_connect (G_OBJECT (but), "clicked", G_CALLBACK (gmdb_sql_save_cb), sqlwin_xml); mi = glade_xml_get_widget (sqlwin_xml, "save_as_menu"); g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (gmdb_sql_save_as_cb), sqlwin_xml); //but = glade_xml_get_widget (sqlwin_xml, "save_as_button"); //g_signal_connect (G_OBJECT (but), "clicked", // G_CALLBACK (gmdb_sql_save_as_cb), sqlwin_xml); mi = glade_xml_get_widget (sqlwin_xml, "results_menu"); g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (gmdb_sql_results_cb), sqlwin_xml); but = glade_xml_get_widget (sqlwin_xml, "results_button"); g_signal_connect (G_OBJECT (but), "clicked", G_CALLBACK (gmdb_sql_results_cb), sqlwin_xml); mi = glade_xml_get_widget (sqlwin_xml, "open_menu"); g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (gmdb_sql_open_cb), sqlwin_xml); but = glade_xml_get_widget (sqlwin_xml, "open_button"); g_signal_connect (G_OBJECT (but), "clicked", G_CALLBACK (gmdb_sql_open_cb), sqlwin_xml); mi = glade_xml_get_widget (sqlwin_xml, "paste_menu"); g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (gmdb_sql_paste_cb), sqlwin_xml); mi = glade_xml_get_widget (sqlwin_xml, "cut_menu"); g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (gmdb_sql_cut_cb), sqlwin_xml); mi = glade_xml_get_widget (sqlwin_xml, "copy_menu"); g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (gmdb_sql_copy_cb), sqlwin_xml); mi = glade_xml_get_widget (sqlwin_xml, "close_menu"); g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (gmdb_sql_close_cb), sqlwin_xml); but = glade_xml_get_widget (sqlwin_xml, "close_button"); g_signal_connect (G_OBJECT (but), "clicked", G_CALLBACK (gmdb_sql_close_cb), sqlwin_xml); mi = glade_xml_get_widget (sqlwin_xml, "execute_menu"); g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (gmdb_sql_execute_cb), sqlwin_xml); combobox = glade_xml_get_widget(sqlwin_xml, "sql_combo"); g_signal_connect (G_OBJECT(GTK_COMBO_BOX(combobox)), "changed", G_CALLBACK (gmdb_sql_select_hist_cb), sqlwin_xml); but = glade_xml_get_widget (sqlwin_xml, "execute_button"); g_signal_connect (G_OBJECT (but), "clicked", G_CALLBACK (gmdb_sql_execute_cb), sqlwin_xml); /* set up treeview, libglade only gives us the empty widget */ GtkWidget *tree = glade_xml_get_widget(sqlwin_xml, "sql_treeview"); GtkTreeStore *store = gtk_tree_store_new(1, G_TYPE_STRING); gtk_tree_view_set_model(GTK_TREE_VIEW(tree), GTK_TREE_MODEL(store)); GtkCellRenderer *renderer; GtkTreeViewColumn *column; renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes("Name", renderer, "text", 0, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW (tree), column); GtkTreeSelection *select = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree)); gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE); //g_signal_connect (G_OBJECT (select), "changed", //G_CALLBACK (gmdb_sql_select_cb), sqlwin_xml); /* populate first level of tree */ gmdb_sql_tree_populate(mdb, sqlwin_xml); GtkWidget *textview = glade_xml_get_widget(sqlwin_xml, "sql_textview"); src.target = "table"; src.flags = 0; src.info = 1; gtk_drag_source_set( tree, GDK_BUTTON1_MASK, &src, 1, GDK_ACTION_COPY); gtk_drag_dest_set( textview, //GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT , // GTK_DEST_DEFAULT_DROP, &src, 1, GDK_ACTION_COPY | GDK_ACTION_MOVE); gtk_signal_connect( GTK_OBJECT(tree), "drag_data_get", GTK_SIGNAL_FUNC(gmdb_sql_dnd_dataget_cb), sqlwin_xml); gtk_signal_connect( GTK_OBJECT(textview), "drag_data_received", GTK_SIGNAL_FUNC(gmdb_sql_dnd_datareceived_cb), sqlwin_xml); //GValue value = {0, }; //but = glade_xml_get_widget(sqlwin_xml, "results_button"); //g_value_init(&value, G_TYPE_STRING); //g_value_set_static_string(&value, GMDB_ICONDIR "stock_export.png"); //g_object_set_property(G_OBJECT (but), "file" , &value); //g_value_unset (&value); gtk_widget_grab_focus(GTK_WIDGET(textview)); } /* functions */ static gchar * gmdb_sql_get_basename(char *file_path) { int i, len; gchar *basename; for (i=strlen(file_path);i>=0 && file_path[i]!='/';i--); len = strlen(file_path) - i + 2; basename = g_malloc(len); if (file_path[i]=='/') { strncpy(basename,&file_path[i+1],len); } else { strncpy(basename,file_path,len); } basename[len]='\0'; return basename; } static void gmdb_sql_set_file(GladeXML *xml, gchar *file_name) { GtkWidget *window, *textview; gchar *title; gchar *basename; gchar *suffix = " - MDB Query Tool"; basename = gmdb_sql_get_basename(file_name); title = g_malloc(strlen(basename) + strlen(suffix) + 1); sprintf(title,"%s%s", basename, suffix); g_free(basename); window = glade_xml_get_widget(xml, "sql_window"); gtk_window_set_title(GTK_WINDOW(window), title); g_free(title); textview = glade_xml_get_widget(xml, "sql_textview"); g_object_set_data(G_OBJECT(textview), "file_name", file_name); } static void gmdb_sql_save_query (GladeXML *xml, gchar *file_path) { FILE *out; GtkWidget *textview; GtkTextBuffer *txtbuffer; GtkTextIter start, end; gchar *buf; if (!(out=fopen(file_path, "w"))) { GtkWidget* dlg = gtk_message_dialog_new (NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, _("Unable to open file.")); gtk_dialog_run (GTK_DIALOG (dlg)); gtk_widget_destroy (dlg); return; } textview = glade_xml_get_widget(xml, "sql_textview"); txtbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview)); gtk_text_buffer_get_start_iter(txtbuffer, &start); gtk_text_buffer_get_end_iter(txtbuffer, &end); buf = gtk_text_buffer_get_text(txtbuffer, &start, &end, FALSE); fprintf(out,"%s\n",buf); fclose(out); gmdb_sql_set_file(xml, file_path); } static void gmdb_sql_load_query(GladeXML *xml, gchar *file_path) { FILE *in; char buf[256]; GtkWidget *textview; GtkTextBuffer *txtbuffer; GtkTextIter start, end; if (!(in=fopen(file_path, "r"))) { GtkWidget* dlg = gtk_message_dialog_new (NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, _("Unable to open file.")); gtk_dialog_run (GTK_DIALOG (dlg)); gtk_widget_destroy (dlg); return; } textview = glade_xml_get_widget(xml, "sql_textview"); txtbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview)); gtk_text_buffer_get_start_iter(txtbuffer, &start); gtk_text_buffer_get_end_iter(txtbuffer, &end); gtk_text_buffer_delete(txtbuffer, &start, &end); while (fgets(buf, 255, in) && (*buf != '\0')) { gtk_text_buffer_get_end_iter(txtbuffer, &end); gtk_text_buffer_insert(txtbuffer, &end, buf, strlen(buf)); } fclose(in); gmdb_sql_set_file(xml, file_path); } static void gmdb_sql_tree_populate(MdbHandle *mdb, GladeXML *xml) { int i; MdbCatalogEntry *entry; GtkTreeIter *iter2; GtkWidget *tree = glade_xml_get_widget(xml, "sql_treeview"); GtkTreeStore *store = (GtkTreeStore *) gtk_tree_view_get_model(GTK_TREE_VIEW(tree)); /* add all user tables in catalog to tab */ for (i=0; i < mdb->num_catalog; i++) { entry = g_ptr_array_index (mdb->catalog, i); if (mdb_is_user_table(entry)) { iter2 = g_malloc(sizeof(GtkTreeIter)); gtk_tree_store_append(store, iter2, NULL); gtk_tree_store_set(store, iter2, 0, entry->object_name, -1); } } /* for */ } #else void gmdb_sql_new_cb (GtkWidget *w, gpointer data) { GtkWidget* dlg = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (w)), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, _("SQL support was not built.\nMake sure flex and yacc are installed at build time.")); gtk_dialog_run (GTK_DIALOG (dlg)); gtk_widget_destroy (dlg); } #endif mdbtools-0.7.1/src/gmdb2/table.c000066400000000000000000000126061222645741400163730ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * 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. */ #include #include #include "gmdb.h" extern GladeXML* mainwin_xml; extern MdbHandle *mdb; int selected_table = -1; /* callbacks */ void gmdb_table_debug_cb(GtkList *list, GtkWidget *w, gpointer data) { MdbCatalogEntry *entry; /* nothing selected yet? */ if (selected_table==-1) { return; } entry = g_ptr_array_index(mdb->catalog,selected_table); gmdb_debug_new_cb(w, (gpointer) &entry->table_pg); } void gmdb_table_def_cb(GtkList *list, GtkWidget *w, gpointer data) { MdbCatalogEntry *entry; /* nothing selected yet? */ if (selected_table==-1) { return; } entry = g_ptr_array_index(mdb->catalog,selected_table); gmdb_table_def_new(entry); } void gmdb_table_export_cb(GtkList *list, GtkWidget *w, gpointer data) { MdbCatalogEntry *entry; /* nothing selected yet? */ if (selected_table==-1) { return; } entry = g_ptr_array_index(mdb->catalog,selected_table); gmdb_table_export(entry); } void gmdb_table_data_cb(GtkList *list, GtkWidget *w, gpointer data) { MdbCatalogEntry *entry; /* nothing selected yet? */ if (selected_table==-1) { return; } entry = g_ptr_array_index(mdb->catalog,selected_table); gmdb_table_data_new(entry); } void gmdb_table_select_cb (GtkIconView* giv, gpointer data) { int i; MdbCatalogEntry *entry; gchar *text; GList *selection; GtkTreeModel *store; GtkTreePath *path; GtkTreeIter iter; selected_table = -1; selection = gtk_icon_view_get_selected_items (giv); if (g_list_length (selection) < 1) { gmdb_table_set_sensitive (FALSE); g_list_free (selection); return; } store = gtk_icon_view_get_model (giv); path = (GtkTreePath*) selection->data; if (!gtk_tree_model_get_iter (store, &iter, path)) { /* FIXME */ g_error ("Failed to get selection iter!!!"); g_list_foreach (selection, (GFunc) gtk_tree_path_free, NULL); g_list_free (selection); } gtk_tree_model_get (store, &iter, 1, &text, -1); for (i=0;inum_catalog;i++) { entry = g_ptr_array_index(mdb->catalog,i); if (entry->object_type==MDB_TABLE && !strcmp(entry->object_name,text)) { selected_table = i; } } g_free (text); if (selected_table>0) { gmdb_table_set_sensitive(TRUE); } else { gmdb_table_set_sensitive(FALSE); } g_list_foreach (selection, (GFunc) gtk_tree_path_free, NULL); g_list_free (selection); } static gboolean gmdb_table_popup_cb (GtkIconView* giv, GdkEvent* event, gpointer data) { GtkWidget* menu = GTK_WIDGET (data); GdkEventButton *event_button; if (event->type == GDK_BUTTON_PRESS) { event_button = (GdkEventButton *) event; if (event_button->button == 3) { GtkTreePath *path = gtk_icon_view_get_path_at_pos (giv, (gint) event_button->x, (gint) event_button->y); if (path) { gtk_icon_view_select_path (giv, path); gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, event_button->button, event_button->time); return TRUE; } } } return FALSE; } /* functions */ void gmdb_table_set_sensitive(gboolean b) { GtkWidget *button; button = (GtkWidget *) glade_xml_get_widget (mainwin_xml, "table_definition"); gtk_widget_set_sensitive(button,b); button = (GtkWidget *) glade_xml_get_widget (mainwin_xml, "table_data"); gtk_widget_set_sensitive(button,b); button = (GtkWidget *) glade_xml_get_widget (mainwin_xml, "table_export"); gtk_widget_set_sensitive(button,b); } void gmdb_table_init_popup (GtkWidget* w) { GtkWidget *menu, *mi; GtkIconView *giv = GTK_ICON_VIEW (w); menu = gtk_menu_new(); gtk_widget_show(menu); mi = gtk_menu_item_new_with_label("Definition"); gtk_widget_show(mi); g_signal_connect_swapped (G_OBJECT (mi), "activate", G_CALLBACK (gmdb_table_def_cb), giv); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi); mi = gtk_menu_item_new_with_label("Data"); gtk_widget_show(mi); g_signal_connect_swapped (G_OBJECT (mi), "activate", G_CALLBACK (gmdb_table_data_cb), giv); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi); mi = gtk_menu_item_new_with_label("Export"); gtk_widget_show(mi); g_signal_connect_swapped (G_OBJECT (mi), "activate", G_CALLBACK (gmdb_table_export_cb), giv); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi); mi = gtk_separator_menu_item_new(); gtk_widget_show(mi); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi); mi = gtk_menu_item_new_with_label("Debug"); gtk_widget_show(mi); g_signal_connect_swapped (G_OBJECT (mi), "activate", G_CALLBACK (gmdb_table_debug_cb), giv); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi); //mi = gtk_menu_item_new_with_label("Usage Map"); //gtk_widget_show(mi); //gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi); g_signal_connect (giv, "button_press_event", G_CALLBACK (gmdb_table_popup_cb), menu); } mdbtools-0.7.1/src/gmdb2/table_data.c000066400000000000000000000065461222645741400173720ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * 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. */ #include "gmdb.h" extern GtkWidget *app; extern MdbHandle *mdb; typedef struct GMdbDataWindow { gchar table_name[MDB_MAX_OBJ_NAME]; GtkWidget *window; } GMdbDataWindow; static GList *window_list; /* callbacks */ static gint gmdb_table_data_close(GtkWidget *w, GdkEvent *event, GMdbDataWindow *dataw) { window_list = g_list_remove(window_list, dataw); g_free(dataw); return FALSE; } /* functions */ GtkWidget * gmdb_table_data_new(MdbCatalogEntry *entry) { MdbTableDef *table; MdbColumn *col; GtkWidget *clist; GtkWidget *scroll; int i; long row, maxrow; gchar *bound_data[256]; GMdbDataWindow *dataw = NULL; /* do we have an active window for this object? if so raise it */ for (i=0;itable_name, entry->object_name)) { gdk_window_raise (dataw->window->window); return dataw->window; } } dataw = g_malloc(sizeof(GMdbDataWindow)); strcpy(dataw->table_name, entry->object_name); dataw->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(dataw->window), entry->object_name); gtk_widget_set_usize(dataw->window, 300,200); gtk_widget_set_uposition(dataw->window, 50,50); gtk_widget_show(dataw->window); gtk_signal_connect (GTK_OBJECT (dataw->window), "delete_event", GTK_SIGNAL_FUNC (gmdb_table_data_close), dataw); scroll = gtk_scrolled_window_new(NULL,NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_widget_show (scroll); gtk_container_add(GTK_CONTAINER(dataw->window), scroll); /* read table */ table = mdb_read_table(entry); mdb_read_columns(table); mdb_rewind_table(table); clist = gtk_clist_new(table->num_cols); gtk_widget_show(clist); gtk_container_add(GTK_CONTAINER(scroll),clist); for (i=0;inum_cols;i++) { /* bind columns */ bound_data[i] = (char *) g_malloc0(MDB_BIND_SIZE); mdb_bind_column(table, i+1, bound_data[i], NULL); /* display column titles */ col=g_ptr_array_index(table->columns,i); gtk_clist_set_column_title(GTK_CLIST(clist), i, col->name); } gtk_clist_column_titles_show(GTK_CLIST(clist)); maxrow = gmdb_prefs_get_maxrows(); /* fetch those rows! */ row = 0; while(mdb_fetch_row(table) && (!maxrow || (row < maxrow))) { row++; gtk_clist_append(GTK_CLIST(clist), bound_data); } /* free the memory used to bind */ for (i=0;inum_cols;i++) { g_free(bound_data[i]); } /* add this one to the window list */ window_list = g_list_append(window_list, dataw); return dataw->window; } mdbtools-0.7.1/src/gmdb2/table_def.c000066400000000000000000000333551222645741400172150ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000-2012 Brian Bruns and others * * 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. */ #include "gmdb.h" #define COL_PK 0 #define COL_NAME 1 #define COL_TYPE 2 #define COL_TYPETEXT 3 #define COL_DESCRIPTION 4 #define COL_LEN 5 #define COL_FORMAT 6 #define COL_DECIMALPLACES 7 #define COL_INPUTMASK 8 #define COL_CAPTION 9 #define COL_DEFAULTVALUE 10 #define COL_VALIDATIONRULE 11 #define COL_VALIDATIONTEXT 12 #define COL_REQUIRED 13 #define COL_ALLOWZEROLENGTH 14 static void update_bottom_properties(GtkTreeView *treeview, GladeXML *xml); typedef struct GMdbDefWindow { gchar table_name[MDB_MAX_OBJ_NAME]; GtkWidget *window; } GMdbDefWindow; static GList *window_list; /* callbacks */ static gint gmdb_table_def_close(GtkList *list, GtkWidget *w, GMdbDefWindow *defw) { window_list = g_list_remove(window_list, defw); g_free(defw); return FALSE; } static gint gmdb_table_def_cursorchanged(GtkTreeView *treeview, GladeXML *xml) { update_bottom_properties(treeview, xml); return FALSE; } void gmdb_table_def_new(MdbCatalogEntry *entry) { /* FIXME: many reference should be freed */ GladeXML *xml; GtkWindow *win; GtkTreeView *treeview; GtkListStore *store; GtkTreeModel *model; GtkTreeIter iter; GtkTreeSelection *selection; int i, j; GMdbDefWindow *defw; MdbTableDef *table; MdbColumn *col; const char *propval; MdbIndex *idx; GdkPixbuf *pixbuf; /* do we have an active window for this object? if so raise it */ for (i=0;itable_name, entry->object_name) && entry->object_type == MDB_TABLE) { gdk_window_raise (defw->window->window); return; } } /* load the interface */ xml = glade_xml_new(GMDB_GLADEDIR "gmdb-tabledef.glade", NULL, NULL); glade_xml_signal_autoconnect(xml); win = GTK_WINDOW(glade_xml_get_widget(xml, "window1")); gtk_window_set_title(win, entry->object_name); gtk_window_set_default_size(win, 600, 400); /* icon to be used as primary key member indicator */ pixbuf = gdk_pixbuf_new_from_file(GMDB_ICONDIR "pk.xpm", NULL); store = gtk_list_store_new(15, GDK_TYPE_PIXBUF, /* part of primary key */ G_TYPE_STRING, /* column name */ G_TYPE_INT, /* type */ G_TYPE_STRING, /* type as text */ G_TYPE_STRING, /* description */ G_TYPE_INT, /* length */ G_TYPE_STRING, /* format */ G_TYPE_INT, /* decimal places */ G_TYPE_STRING, /* inputmask */ G_TYPE_STRING, /* caption */ G_TYPE_STRING, /* default value */ G_TYPE_STRING, /* validation rule */ G_TYPE_STRING, /* validation text */ G_TYPE_BOOLEAN, /* required */ G_TYPE_BOOLEAN /* allow zero length */ ); /* read table */ table = mdb_read_table(entry); mdb_read_columns(table); mdb_rewind_table(table); for (i=0;inum_cols;i++) { int required = 0; gtk_list_store_append (store, &iter); col=g_ptr_array_index(table->columns,i); gtk_list_store_set (store, &iter, COL_NAME, col->name, COL_TYPE, col->col_type, COL_TYPETEXT, mdb_get_colbacktype_string(col), COL_LEN, col->col_size, COL_REQUIRED, 0, -1); propval = mdb_col_get_prop(col, "Description"); if (propval) gtk_list_store_set (store, &iter, COL_DESCRIPTION, propval, -1); propval = mdb_col_get_prop(col, "Format"); if (propval) gtk_list_store_set (store, &iter, COL_FORMAT, propval, -1); propval = mdb_col_get_prop(col, "DecimalPlaces"); if (propval) gtk_list_store_set (store, &iter, COL_DECIMALPLACES, atoi(propval), -1); propval = mdb_col_get_prop(col, "InputMask"); if (propval) gtk_list_store_set (store, &iter, COL_INPUTMASK, propval, -1); propval = mdb_col_get_prop(col, "Caption"); if (propval) gtk_list_store_set (store, &iter, COL_CAPTION, propval, -1); propval = mdb_col_get_prop(col, "DefaultValue"); if (propval) gtk_list_store_set (store, &iter, COL_DEFAULTVALUE, propval, -1); propval = mdb_col_get_prop(col, "ValidationRule"); if (propval) gtk_list_store_set (store, &iter, COL_VALIDATIONRULE, propval, -1); propval = mdb_col_get_prop(col, "ValidationText"); if (propval) gtk_list_store_set (store, &iter, COL_VALIDATIONTEXT, propval, -1); propval = mdb_col_get_prop(col, "AllowZeroLength"); if (propval) gtk_list_store_set (store, &iter, COL_ALLOWZEROLENGTH, propval, -1); if (col->col_type == MDB_BOOL) required = 1; else { propval = mdb_col_get_prop(col, "Required"); if (propval && propval[0]=='y') required = 1; } gtk_list_store_set (store, &iter, COL_REQUIRED, required, -1); } model = GTK_TREE_MODEL(store); mdb_read_indices(table); for (i=0;inum_idxs;i++) { idx = g_ptr_array_index (table->indices, i); if (idx->index_type==1) for (j=0;jnum_keys;j++) { gtk_tree_model_iter_nth_child(model, &iter, NULL, idx->key_col_num[j]-1); gtk_list_store_set (store, &iter, COL_PK, pixbuf, -1); } } treeview = GTK_TREE_VIEW(glade_xml_get_widget(xml, "columns_treeview")); gtk_tree_view_insert_column_with_attributes (treeview, -1, "PK", gtk_cell_renderer_pixbuf_new(), "pixbuf", COL_PK, NULL); gtk_tree_view_insert_column_with_attributes (treeview, -1, "Name", gtk_cell_renderer_text_new(), "text", COL_NAME, NULL); gtk_tree_view_insert_column_with_attributes (treeview, -1, "Type", gtk_cell_renderer_text_new(), "text", COL_TYPETEXT, NULL); gtk_tree_view_insert_column_with_attributes (treeview, -1, "Description", gtk_cell_renderer_text_new(), "text", COL_DESCRIPTION, NULL); gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), model); /* The tree view has acquired its own reference to the * model, so we can drop ours. That way the model will * be freed automatically when the tree view is destroyed */ g_object_unref (model); /* select first item */ gtk_tree_model_iter_nth_child(model, &iter, NULL, 0); selection = gtk_tree_view_get_selection(treeview); gtk_tree_selection_select_iter(selection, &iter); update_bottom_properties(treeview, xml); gtk_widget_show(GTK_WIDGET(win)); defw = g_malloc(sizeof(GMdbDefWindow)); strcpy(defw->table_name, entry->object_name); defw->window = GTK_WIDGET(win); window_list = g_list_append(window_list, defw); gtk_signal_connect (GTK_OBJECT (treeview), "cursor-changed", GTK_SIGNAL_FUNC (gmdb_table_def_cursorchanged), xml); gtk_signal_connect (GTK_OBJECT (defw->window), "delete_event", GTK_SIGNAL_FUNC (gmdb_table_def_close), defw); } /* That function is called when selection is changed * It updates the window bottom information */ static void update_bottom_properties_selected(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, GladeXML *xml) { char tmp[20]; gint col_type; gint size; char *format; gint decimalplaces; char *inputmask; char *caption; char *defaultvalue; char *validationrule; char *validationtext; gboolean required; gboolean allowzerolength; GtkLabel *label; GtkEntry *entry; gtk_tree_model_get(model, iter, COL_TYPE, &col_type, COL_LEN, &size, COL_FORMAT, &format, COL_DECIMALPLACES, &decimalplaces, COL_INPUTMASK, &inputmask, COL_CAPTION, &caption, COL_DEFAULTVALUE, &defaultvalue, COL_VALIDATIONRULE, &validationrule, COL_VALIDATIONTEXT, &validationtext, COL_REQUIRED, &required, COL_ALLOWZEROLENGTH, &allowzerolength, -1); //fprintf(stderr, "type=%d\n", col_type); label = GTK_LABEL(glade_xml_get_widget(xml, "size_label")); entry = GTK_ENTRY(glade_xml_get_widget(xml, "size_entry")); switch (col_type) { //case MDB_BOOL: case MDB_BYTE: case MDB_INT: case MDB_LONGINT: case MDB_MONEY: case MDB_FLOAT: case MDB_DOUBLE: case MDB_DATETIME: //case MDB_BINARY: //case MDB_TEXT: //case MDB_OLE: //case MDB_MEMO: //case MDB_REPID: //case MDB_NUMERIC: //case MDB_COMPLEX: gtk_widget_show(GTK_WIDGET(label)); gtk_widget_show(GTK_WIDGET(entry)); sprintf(tmp, "%d", size); gtk_entry_set_text(entry, tmp); break; default: gtk_widget_hide(GTK_WIDGET(label)); gtk_widget_hide(GTK_WIDGET(entry)); } label = GTK_LABEL(glade_xml_get_widget(xml, "format_label")); entry = GTK_ENTRY(glade_xml_get_widget(xml, "format_entry")); switch (col_type) { case MDB_BOOL: case MDB_BYTE: case MDB_INT: case MDB_LONGINT: case MDB_MONEY: case MDB_FLOAT: case MDB_DOUBLE: case MDB_DATETIME: //case MDB_BINARY: case MDB_TEXT: //case MDB_OLE: case MDB_MEMO: //case MDB_REPID: //case MDB_NUMERIC: //case MDB_COMPLEX: gtk_widget_show(GTK_WIDGET(label)); gtk_widget_show(GTK_WIDGET(entry)); sprintf(tmp, "%d", size); gtk_entry_set_text(entry, format ? format : ""); break; default: gtk_widget_hide(GTK_WIDGET(label)); gtk_widget_hide(GTK_WIDGET(entry)); } g_free(format); label = GTK_LABEL(glade_xml_get_widget(xml, "decimalplaces_label")); entry = GTK_ENTRY(glade_xml_get_widget(xml, "decimalplaces_entry")); switch (col_type) { case MDB_BYTE: case MDB_INT: case MDB_LONGINT: case MDB_FLOAT: case MDB_DOUBLE: gtk_widget_show(GTK_WIDGET(label)); gtk_widget_show(GTK_WIDGET(entry)); if (decimalplaces) { sprintf(tmp, "%d", decimalplaces); gtk_entry_set_text(entry, tmp); } else gtk_entry_set_text(entry, ""); break; default: gtk_widget_hide(GTK_WIDGET(label)); gtk_widget_hide(GTK_WIDGET(entry)); } label = GTK_LABEL(glade_xml_get_widget(xml, "inputmask_label")); entry = GTK_ENTRY(glade_xml_get_widget(xml, "inputmask_entry")); switch (col_type) { //case MDB_BOOL: case MDB_BYTE: case MDB_INT: case MDB_LONGINT: case MDB_MONEY: case MDB_FLOAT: case MDB_DOUBLE: case MDB_DATETIME: //case MDB_BINARY: case MDB_TEXT: //case MDB_OLE: case MDB_MEMO: //case MDB_REPID: //case MDB_NUMERIC: //case MDB_COMPLEX: gtk_widget_show(GTK_WIDGET(label)); gtk_widget_show(GTK_WIDGET(entry)); gtk_entry_set_text(entry, inputmask ? inputmask : ""); break; default: gtk_widget_hide(GTK_WIDGET(label)); gtk_widget_hide(GTK_WIDGET(entry)); } g_free(inputmask); entry = GTK_ENTRY(glade_xml_get_widget(xml, "caption_entry")); gtk_entry_set_text(entry, caption ? caption : ""); g_free(caption); label = GTK_LABEL(glade_xml_get_widget(xml, "defaultvalue_label")); entry = GTK_ENTRY(glade_xml_get_widget(xml, "defaultvalue_entry")); switch (col_type) { case MDB_BOOL: case MDB_BYTE: case MDB_INT: case MDB_LONGINT: case MDB_MONEY: case MDB_FLOAT: case MDB_DOUBLE: case MDB_DATETIME: //case MDB_BINARY: case MDB_TEXT: //case MDB_OLE: //case MDB_MEMO: //case MDB_REPID: //case MDB_NUMERIC: //case MDB_COMPLEX: gtk_widget_show(GTK_WIDGET(label)); gtk_widget_show(GTK_WIDGET(entry)); gtk_entry_set_text(entry, defaultvalue ? defaultvalue : ""); default: gtk_widget_hide(GTK_WIDGET(label)); gtk_widget_hide(GTK_WIDGET(entry)); } g_free(defaultvalue); label = GTK_LABEL(glade_xml_get_widget(xml, "validationrule_label")); entry = GTK_ENTRY(glade_xml_get_widget(xml, "validationrule_entry")); switch (col_type) { case MDB_BOOL: case MDB_BYTE: case MDB_INT: case MDB_LONGINT: case MDB_MONEY: case MDB_FLOAT: case MDB_DOUBLE: case MDB_DATETIME: //case MDB_BINARY: case MDB_TEXT: //case MDB_OLE: case MDB_MEMO: //case MDB_REPID: //case MDB_NUMERIC: //case MDB_COMPLEX: gtk_widget_show(GTK_WIDGET(label)); gtk_widget_show(GTK_WIDGET(entry)); gtk_entry_set_text(entry, validationrule ? validationrule : ""); break; default: gtk_widget_hide(GTK_WIDGET(label)); gtk_widget_hide(GTK_WIDGET(entry)); } g_free(validationrule); label = GTK_LABEL(glade_xml_get_widget(xml, "validationtext_label")); entry = GTK_ENTRY(glade_xml_get_widget(xml, "validationtext_entry")); switch (col_type) { case MDB_BOOL: case MDB_BYTE: case MDB_INT: case MDB_LONGINT: case MDB_MONEY: case MDB_FLOAT: case MDB_DOUBLE: case MDB_DATETIME: //case MDB_BINARY: case MDB_TEXT: //case MDB_OLE: case MDB_MEMO: //case MDB_REPID: //case MDB_NUMERIC: //case MDB_COMPLEX: gtk_widget_show(GTK_WIDGET(label)); gtk_widget_show(GTK_WIDGET(entry)); gtk_entry_set_text(entry, validationtext ? validationtext : ""); break; default: gtk_widget_hide(GTK_WIDGET(label)); gtk_widget_hide(GTK_WIDGET(entry)); } g_free(validationtext); entry = GTK_ENTRY(glade_xml_get_widget(xml, "required_entry")); gtk_entry_set_text(entry, required ? "Yes" : "No"); label = GTK_LABEL(glade_xml_get_widget(xml, "allowzerolength_label")); entry = GTK_ENTRY(glade_xml_get_widget(xml, "allowzerolength_entry")); switch (col_type) { //case MDB_BOOL: //case MDB_BYTE: //case MDB_INT: //case MDB_LONGINT: //case MDB_MONEY: //case MDB_FLOAT: //case MDB_DOUBLE: //case MDB_DATETIME: //case MDB_BINARY: case MDB_TEXT: //case MDB_OLE: case MDB_MEMO: //case MDB_REPID: //case MDB_NUMERIC: //case MDB_COMPLEX: gtk_widget_show(GTK_WIDGET(label)); gtk_widget_show(GTK_WIDGET(entry)); gtk_entry_set_text(entry, allowzerolength ? "Yes" : "No"); break; default: gtk_widget_hide(GTK_WIDGET(label)); gtk_widget_hide(GTK_WIDGET(entry)); } } static void update_bottom_properties(GtkTreeView *treeview, GladeXML *xml) { GtkTreeSelection *selection; selection = gtk_tree_view_get_selection(treeview); gtk_tree_selection_selected_foreach(selection, (GtkTreeSelectionForeachFunc)update_bottom_properties_selected, xml); } mdbtools-0.7.1/src/gmdb2/table_export.c000066400000000000000000000251201222645741400177670ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * 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. */ #include #include #include #include #include "gmdb.h" extern GtkWidget *app; extern MdbHandle *mdb; GladeXML *exportwin_xml; MdbCatalogEntry *cat_entry; #define COMMA "Comma (,)" #define TAB "Tab" #define SPACE "Space" #define COLON "Colon (:)" #define SEMICOLON "Semicolon (;)" #define PIPE "Pipe (|)" #define LF "Unix (linefeed only)" #define CR "Mac (carriage return only)" #define CRLF "Windows (CR + LF)" #define ALWAYS "Always" #define NEVER "Never" #define AUTOMAT "Automatic (where necessary)" #define NOQUOTE "Don't quote" #define BIN_STRIP "Strip" #define BIN_RAW "Raw" #define BIN_OCTAL "Octal" void gmdb_export_get_delimiter(GladeXML *xml, gchar *delimiter, int max_buf) { GtkComboBox *combobox; gchar *str; combobox = GTK_COMBO_BOX(glade_xml_get_widget(xml, "sep_combo")); str = gtk_combo_box_get_active_text(combobox); if (!strcmp(str,COMMA)) strncpy(delimiter, ",", max_buf); else if (!strcmp(str,TAB)) strncpy(delimiter, "\t", max_buf); else if (!strcmp(str,SPACE)) strncpy(delimiter, " ", max_buf); else if (!strcmp(str,COLON)) strncpy(delimiter, ":", max_buf); else if (!strcmp(str,SEMICOLON)) strncpy(delimiter, ";", max_buf); else if (!strcmp(str,PIPE)) strncpy(delimiter, "|", max_buf); else strncpy(delimiter, str, max_buf); if (max_buf) delimiter[max_buf-1] = '\0'; } void gmdb_export_get_lineterm(GladeXML *xml, gchar *lineterm, int max_buf) { GtkComboBox *combobox; gchar *str; combobox = GTK_COMBO_BOX(glade_xml_get_widget(xml, "term_combo")); str = gtk_combo_box_get_active_text (combobox); if (!strcmp(str,LF)) strncpy(lineterm, "\n", max_buf); else if (!strcmp(str,CR)) strncpy(lineterm, "\r", max_buf); else if (!strcmp(str,CRLF)) strncpy(lineterm, "\r\n", max_buf); if (max_buf) lineterm[max_buf-1] = '\0'; } void gmdb_export_get_quotechar(GladeXML *xml, gchar *quotechar, int max_buf) { GtkComboBox *combobox; gchar *str; combobox = GTK_COMBO_BOX(glade_xml_get_widget(xml, "qchar_combo")); str = gtk_combo_box_get_active_text (combobox); if (!strcmp(str, NOQUOTE)) quotechar[0] = '\0'; /* Quoting disabled */ else strncpy(quotechar, str, max_buf); if (max_buf) quotechar[max_buf-1] = '\0'; } void gmdb_export_get_escapechar(GladeXML *xml, gchar *escapechar, int max_buf) { GtkComboBox *combobox; gchar *str; combobox = GTK_COMBO_BOX(glade_xml_get_widget(xml, "escchar_combo")); str = gtk_combo_box_get_active_text (combobox); strncpy(escapechar, str, max_buf); if (max_buf) escapechar[max_buf-1] = '\0'; } int gmdb_export_get_binmode(GladeXML *xml) { GtkComboBox *combobox; gchar *str; combobox = GTK_COMBO_BOX(glade_xml_get_widget(xml, "bin_combo")); str = gtk_combo_box_get_active_text (combobox); if (!strcmp(str,BIN_STRIP)) return MDB_BINEXPORT_STRIP; else if (!strcmp(str,BIN_OCTAL)) return MDB_BINEXPORT_OCTAL; else return MDB_BINEXPORT_RAW; } int gmdb_export_get_headers(GladeXML *xml) { GtkWidget *checkbox; checkbox = glade_xml_get_widget(xml, "headers_checkbox"); if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbox))) return 1; else return 0; } gchar * gmdb_export_get_filepath(GladeXML *xml) { GtkWidget *fchoose; fchoose = glade_xml_get_widget(xml, "filename_entry"); return (gchar *) gtk_entry_get_text (GTK_ENTRY (fchoose)); } void gmdb_export_help_cb(GtkWidget *w, gpointer data) { GError *error = NULL; gnome_help_display("gmdb.xml", "gmdb-table-export", &error); if (error != NULL) { g_warning ("%s", error->message); g_error_free (error); } } /* That function is a duplicate of the one in util/mdb-export.c * They should be merged and moved in libmdb (backend.c) */ #define is_quote_type(x) (x==MDB_TEXT || x==MDB_OLE || x==MDB_MEMO || x==MDB_DATETIME || x==MDB_BINARY || x==MDB_REPID) #define is_binary_type(x) (x==MDB_OLE || x==MDB_BINARY || x==MDB_REPID) //#define DONT_ESCAPE_ESCAPE void gmdb_print_col(FILE *outfile, gchar *col_val, int quote_text, int col_type, int bin_len, char *quote_char, char *escape_char, int bin_mode) { size_t quote_len = strlen(quote_char); /* multibyte */ size_t orig_escape_len = escape_char ? strlen(escape_char) : 0; /* double the quote char if no escape char passed */ if (!escape_char) escape_char = quote_char; if (quote_text && is_quote_type(col_type)) { fputs(quote_char, outfile); while (1) { if (is_binary_type(col_type)) { if (bin_mode == MDB_BINEXPORT_STRIP) break; if (!bin_len--) break; } else /* use \0 sentry */ if (!*col_val) break; if (quote_len && !strncmp(col_val, quote_char, quote_len)) { fprintf(outfile, "%s%s", escape_char, quote_char); col_val += quote_len; #ifndef DONT_ESCAPE_ESCAPE } else if (orig_escape_len && !strncmp(col_val, escape_char, orig_escape_len)) { fprintf(outfile, "%s%s", escape_char, escape_char); col_val += orig_escape_len; #endif } else if (is_binary_type(col_type) && *col_val <= 0 && bin_mode == MDB_BINEXPORT_OCTAL) fprintf(outfile, "\\%03o", *(unsigned char*)col_val++); else putc(*col_val++, outfile); } fputs(quote_char, outfile); } else fputs(col_val, outfile); } void gmdb_table_export_button_cb(GtkWidget *w, gpointer data) { gchar *file_path; FILE *outfile; char **bound_values; int *bound_lens; MdbTableDef *table; MdbColumn *col; int i; int need_headers = 0; gchar delimiter[11]; gchar quotechar[5]; gchar escape_char[5]; gchar lineterm[5]; int bin_mode = MDB_BINEXPORT_RAW; int rows=0; char *value; size_t length; GtkWidget *exportwin, *dlg; gmdb_export_get_delimiter(exportwin_xml, delimiter, sizeof(delimiter)); gmdb_export_get_lineterm(exportwin_xml, lineterm, sizeof(lineterm)); gmdb_export_get_quotechar(exportwin_xml, quotechar, sizeof(quotechar)); gmdb_export_get_escapechar(exportwin_xml, escape_char, sizeof(escape_char)); need_headers = gmdb_export_get_headers(exportwin_xml); bin_mode = gmdb_export_get_binmode(exportwin_xml); file_path = gmdb_export_get_filepath(exportwin_xml); // printf("file path %s\n",file_path); if ((outfile=fopen(file_path, "w"))==NULL) { GtkWidget* dlg = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (w)), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, _("Unable to open file.")); gtk_dialog_run (GTK_DIALOG (dlg)); gtk_widget_destroy (dlg); return; } /* read table */ table = mdb_read_table(cat_entry); mdb_read_columns(table); mdb_rewind_table(table); bound_values = (char **) g_malloc(table->num_cols * sizeof(char *)); bound_lens = (int *) g_malloc(table->num_cols * sizeof(int)); for (i=0;inum_cols;i++) { /* bind columns */ bound_values[i] = (char *) g_malloc0(MDB_BIND_SIZE); mdb_bind_column(table, i+1, bound_values[i], &bound_lens[i]); /* display column titles */ if (need_headers) { if (i>0) fputs(delimiter, outfile); col=g_ptr_array_index(table->columns,i); gmdb_print_col(outfile, col->name, quotechar[0]!='\0', MDB_TEXT, 0, quotechar, escape_char, bin_mode); } } if (need_headers) fputs(lineterm, outfile); /* fetch those rows! */ while(mdb_fetch_row(table)) { for (i=0;inum_cols;i++) { if (i>0) fputs(delimiter, outfile); col=g_ptr_array_index(table->columns,i); /* Don't quote NULLs */ if (bound_lens[i]) { if (col->col_type == MDB_OLE) { value = mdb_ole_read_full(mdb, col, &length); } else { value = bound_values[i]; length = bound_lens[i]; } gmdb_print_col(outfile, value, quotechar[0]!='\0', col->col_type, length, quotechar, escape_char, bin_mode); if (col->col_type == MDB_OLE) free(value); } } fputs(lineterm, outfile); rows++; } /* free the memory used to bind */ for (i=0;inum_cols;i++) { g_free(bound_values[i]); } g_free(bound_values); g_free(bound_lens); fclose(outfile); exportwin = glade_xml_get_widget (exportwin_xml, "export_dialog"); gtk_widget_destroy(exportwin); dlg = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (w)), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, _("%d rows successfully exported."), rows); gtk_dialog_run (GTK_DIALOG (dlg)); gtk_widget_destroy (dlg); } void gmdb_table_export(MdbCatalogEntry *entry) { cat_entry = entry; /* load the interface */ exportwin_xml = glade_xml_new(GMDB_GLADEDIR "gmdb-export.glade", NULL, NULL); /* connect the signals in the interface */ glade_xml_signal_autoconnect(exportwin_xml); gmdb_table_export_populate_dialog(exportwin_xml); } void gmdb_table_export_populate_dialog(GladeXML *xml) { GtkComboBox *combobox; /* Populate the widgets */ combobox = GTK_COMBO_BOX(glade_xml_get_widget(xml, "term_combo")); gtk_combo_box_append_text(combobox, LF); gtk_combo_box_append_text(combobox, CR); gtk_combo_box_append_text(combobox, CRLF); gtk_combo_box_set_active(combobox, 0); combobox = GTK_COMBO_BOX(glade_xml_get_widget(xml, "sep_combo")); gtk_combo_box_append_text(combobox, COMMA); gtk_combo_box_append_text(combobox, TAB); gtk_combo_box_append_text(combobox, SPACE); gtk_combo_box_append_text(combobox, COLON); gtk_combo_box_append_text(combobox, SEMICOLON); gtk_combo_box_append_text(combobox, PIPE); gtk_combo_box_set_active(combobox, 0); combobox = GTK_COMBO_BOX(glade_xml_get_widget(xml, "qchar_combo")); gtk_combo_box_append_text(combobox, "\""); gtk_combo_box_append_text(combobox, "'"); gtk_combo_box_append_text(combobox, "`"); gtk_combo_box_append_text(combobox, NOQUOTE); gtk_combo_box_set_active(combobox, 0); combobox = GTK_COMBO_BOX(glade_xml_get_widget(xml, "escchar_combo")); gtk_combo_box_append_text(combobox, "\\"); gtk_combo_box_set_active(combobox, 0); combobox = GTK_COMBO_BOX(glade_xml_get_widget(xml, "bin_combo")); gtk_combo_box_append_text(combobox, BIN_STRIP); gtk_combo_box_append_text(combobox, BIN_RAW); gtk_combo_box_append_text(combobox, BIN_OCTAL); gtk_combo_box_set_active(combobox, 1); } mdbtools-0.7.1/src/libmdb/000077500000000000000000000000001222645741400153715ustar00rootroot00000000000000mdbtools-0.7.1/src/libmdb/Makefile.am000066400000000000000000000006041222645741400174250ustar00rootroot00000000000000lib_LTLIBRARIES = libmdb.la libmdb_la_SOURCES= catalog.c mem.c file.c table.c data.c dump.c backend.c money.c sargs.c index.c like.c write.c stats.c map.c props.c worktable.c options.c iconv.c libmdb_la_LDFLAGS = -version-info 2:1:0 -export-symbols-regex '^(mdb_|_mdb_put_int16$$|_mdb_put_int32$$)' AM_CFLAGS = -I$(top_srcdir)/include $(GLIB_CFLAGS) LIBS = $(GLIB_LIBS) @LIBS@ @LIBICONV@ mdbtools-0.7.1/src/libmdb/backend.c000066400000000000000000000677441222645741400171460ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database files * Copyright (C) 2000-2011 Brian Bruns and others * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef JAVA #include "javadefines.h" #define MdbBackendType_STRUCT_ELEMENT(a,b,c,d) new MdbBackendType(a,b,c,d) #else #define MdbBackendType_STRUCT_ELEMENT(a,b,c,d) {a,b,c,d} /* ** functions to deal with different backend database engines */ # #include "mdbtools.h" #ifdef DMALLOC #include "dmalloc.h" #endif #endif /* JAVA */ static int is_init; GHashTable *mdb_backends; void _mdb_remove_backends(); /* Access data types */ static MdbBackendType mdb_access_types[] = { MdbBackendType_STRUCT_ELEMENT("Unknown 0x00", 0,0,0), MdbBackendType_STRUCT_ELEMENT("Boolean", 0,0,0), MdbBackendType_STRUCT_ELEMENT("Byte", 0,0,0), MdbBackendType_STRUCT_ELEMENT("Integer", 0,0,0), MdbBackendType_STRUCT_ELEMENT("Long Integer", 0,0,0), MdbBackendType_STRUCT_ELEMENT("Currency", 0,0,0), MdbBackendType_STRUCT_ELEMENT("Single", 0,0,0), MdbBackendType_STRUCT_ELEMENT("Double", 0,0,0), MdbBackendType_STRUCT_ELEMENT("DateTime", 0,0,1), MdbBackendType_STRUCT_ELEMENT("Binary", 0,0,0), MdbBackendType_STRUCT_ELEMENT("Text", 1,0,1), MdbBackendType_STRUCT_ELEMENT("OLE", 1,0,1), MdbBackendType_STRUCT_ELEMENT("Memo/Hyperlink",1,0,1), MdbBackendType_STRUCT_ELEMENT("Unknown 0x0d",0,0,0), MdbBackendType_STRUCT_ELEMENT("Unknown 0x0e",0,0,0), MdbBackendType_STRUCT_ELEMENT("Replication ID",0,0,0), MdbBackendType_STRUCT_ELEMENT("Numeric",1,1,0) }; /* Oracle data types */ static MdbBackendType mdb_oracle_types[] = { MdbBackendType_STRUCT_ELEMENT("Oracle_Unknown 0x00",0,0,0), MdbBackendType_STRUCT_ELEMENT("NUMBER(1)",0,0,0), MdbBackendType_STRUCT_ELEMENT("NUMBER(3)",0,0,0), MdbBackendType_STRUCT_ELEMENT("NUMBER(5)",0,0,0), MdbBackendType_STRUCT_ELEMENT("NUMBER(11)",0,0,0), MdbBackendType_STRUCT_ELEMENT("NUMBER(15,2)",0,0,0), MdbBackendType_STRUCT_ELEMENT("FLOAT",0,0,0), MdbBackendType_STRUCT_ELEMENT("FLOAT",0,0,0), MdbBackendType_STRUCT_ELEMENT("TIMESTAMP",0,0,0), MdbBackendType_STRUCT_ELEMENT("BINARY",0,0,0), MdbBackendType_STRUCT_ELEMENT("VARCHAR2",1,0,1), MdbBackendType_STRUCT_ELEMENT("BLOB",1,0,1), MdbBackendType_STRUCT_ELEMENT("CLOB",1,0,1), MdbBackendType_STRUCT_ELEMENT("Oracle_Unknown 0x0d",0,0,0), MdbBackendType_STRUCT_ELEMENT("Oracle_Unknown 0x0e",0,0,0), MdbBackendType_STRUCT_ELEMENT("NUMBER",1,0,0), MdbBackendType_STRUCT_ELEMENT("NUMBER",1,0,0), }; static MdbBackendType mdb_oracle_shortdate_type = MdbBackendType_STRUCT_ELEMENT("DATE",0,0,0); /* Sybase/MSSQL data types */ static MdbBackendType mdb_sybase_types[] = { MdbBackendType_STRUCT_ELEMENT("Sybase_Unknown 0x00",0,0,0), MdbBackendType_STRUCT_ELEMENT("bit",0,0,0), MdbBackendType_STRUCT_ELEMENT("char",1,0,1), MdbBackendType_STRUCT_ELEMENT("smallint",0,0,0), MdbBackendType_STRUCT_ELEMENT("int",0,0,0), MdbBackendType_STRUCT_ELEMENT("money",0,0,0), MdbBackendType_STRUCT_ELEMENT("real",0,0,0), MdbBackendType_STRUCT_ELEMENT("float",0,0,0), MdbBackendType_STRUCT_ELEMENT("smalldatetime",0,0,0), MdbBackendType_STRUCT_ELEMENT("Sybase_Unknown 0x09",0,0,0), MdbBackendType_STRUCT_ELEMENT("varchar",1,0,1), MdbBackendType_STRUCT_ELEMENT("varbinary",1,0,1), MdbBackendType_STRUCT_ELEMENT("text",1,0,1), MdbBackendType_STRUCT_ELEMENT("Sybase_Unknown 0x0d",0,0,0), MdbBackendType_STRUCT_ELEMENT("Sybase_Unknown 0x0e",0,0,0), MdbBackendType_STRUCT_ELEMENT("Sybase_Replication ID",0,0,0), MdbBackendType_STRUCT_ELEMENT("numeric",1,1,0), }; static MdbBackendType mdb_sybase_shortdate_type = MdbBackendType_STRUCT_ELEMENT("DATE",0,0,0); /* Postgres data types */ static MdbBackendType mdb_postgres_types[] = { MdbBackendType_STRUCT_ELEMENT("Postgres_Unknown 0x00",0,0,0), MdbBackendType_STRUCT_ELEMENT("BOOL",0,0,0), MdbBackendType_STRUCT_ELEMENT("SMALLINT",0,0,0), MdbBackendType_STRUCT_ELEMENT("INTEGER",0,0,0), MdbBackendType_STRUCT_ELEMENT("INTEGER",0,0,0), /* bigint */ MdbBackendType_STRUCT_ELEMENT("NUMERIC(15,2)",0,0,0), /* money deprecated ? */ MdbBackendType_STRUCT_ELEMENT("REAL",0,0,0), MdbBackendType_STRUCT_ELEMENT("DOUBLE PRECISION",0,0,0), MdbBackendType_STRUCT_ELEMENT("TIMESTAMP WITHOUT TIME ZONE",0,0,0), MdbBackendType_STRUCT_ELEMENT("BYTEA",0,0,0), MdbBackendType_STRUCT_ELEMENT("VARCHAR",1,0,1), MdbBackendType_STRUCT_ELEMENT("BYTEA",0,0,0), MdbBackendType_STRUCT_ELEMENT("TEXT",0,0,0), MdbBackendType_STRUCT_ELEMENT("Postgres_Unknown 0x0d",0,0,0), MdbBackendType_STRUCT_ELEMENT("Postgres_Unknown 0x0e",0,0,0), MdbBackendType_STRUCT_ELEMENT("UUID",0,0,0), MdbBackendType_STRUCT_ELEMENT("Postgres_Unknown 0x10",0,0,0), }; static MdbBackendType mdb_postgres_shortdate_type = MdbBackendType_STRUCT_ELEMENT("DATE",0,0,0); static MdbBackendType mdb_postgres_serial_type = MdbBackendType_STRUCT_ELEMENT("SERIAL",0,0,0); /* MySQL data types */ static MdbBackendType mdb_mysql_types[] = { MdbBackendType_STRUCT_ELEMENT("Text",1,0,1), MdbBackendType_STRUCT_ELEMENT("char",0,0,0), MdbBackendType_STRUCT_ELEMENT("int",0,0,0), MdbBackendType_STRUCT_ELEMENT("int",0,0,0), MdbBackendType_STRUCT_ELEMENT("int",0,0,0), MdbBackendType_STRUCT_ELEMENT("float",0,0,0), MdbBackendType_STRUCT_ELEMENT("float",0,0,0), MdbBackendType_STRUCT_ELEMENT("float",0,0,0), MdbBackendType_STRUCT_ELEMENT("datetime",0,0,1), MdbBackendType_STRUCT_ELEMENT("varchar",1,0,1), MdbBackendType_STRUCT_ELEMENT("varchar",1,0,1), MdbBackendType_STRUCT_ELEMENT("varchar",1,0,1), MdbBackendType_STRUCT_ELEMENT("text",1,0,1), MdbBackendType_STRUCT_ELEMENT("blob",0,0,0), MdbBackendType_STRUCT_ELEMENT("text",1,0,1), MdbBackendType_STRUCT_ELEMENT("char(38)",0,0,0), MdbBackendType_STRUCT_ELEMENT("numeric",1,1,0), }; static MdbBackendType mdb_mysql_shortdate_type = MdbBackendType_STRUCT_ELEMENT("date",0,0,0); /* sqlite data types */ static MdbBackendType mdb_sqlite_types[] = { MdbBackendType_STRUCT_ELEMENT("BLOB", 0,0,0), MdbBackendType_STRUCT_ELEMENT("INTEGER", 0,0,0), MdbBackendType_STRUCT_ELEMENT("INTEGER", 0,0,0), MdbBackendType_STRUCT_ELEMENT("INTEGER", 0,0,0), MdbBackendType_STRUCT_ELEMENT("INTEGER", 0,0,0), MdbBackendType_STRUCT_ELEMENT("REAL", 0,0,0), MdbBackendType_STRUCT_ELEMENT("REAL", 0,0,0), MdbBackendType_STRUCT_ELEMENT("REAL", 0,0,0), MdbBackendType_STRUCT_ELEMENT("DateTime", 0,0,1), MdbBackendType_STRUCT_ELEMENT("BLOB", 0,0,1), MdbBackendType_STRUCT_ELEMENT("varchar", 0,0,1), MdbBackendType_STRUCT_ELEMENT("BLOB", 0,0,1), MdbBackendType_STRUCT_ELEMENT("TEXT", 0,0,1), MdbBackendType_STRUCT_ELEMENT("BLOB", 0,0,1), MdbBackendType_STRUCT_ELEMENT("BLOB", 0,0,1), MdbBackendType_STRUCT_ELEMENT("INTEGER", 0,0,0), MdbBackendType_STRUCT_ELEMENT("INTEGER", 0,0,0), }; #ifndef JAVA static gboolean mdb_drop_backend(gpointer key, gpointer value, gpointer data); static gchar* quote_generic(const gchar *value, gchar quote_char, gchar escape_char) { gchar *result, *pr; unsigned char c; pr = result = g_malloc(1+4*strlen(value)+2); // worst case scenario *pr++ = quote_char; while ((c=*(unsigned char*)value++)) { if (c<32) { sprintf(pr, "\\%03o", c); pr+=4; continue; } else if (c == quote_char) { *pr++ = escape_char; } *pr++ = c; } *pr++ = quote_char; *pr++ = '\0'; return result; } static gchar* quote_schema_name_bracket_merge(const gchar* schema, const gchar *name) { if (schema) return g_strconcat("[", schema, "_", name, "]", NULL); else return g_strconcat("[", name, "]", NULL); } /* * For backends that really does support schema * returns "name" or "schema"."name" */ static gchar* quote_schema_name_dquote(const gchar* schema, const gchar *name) { if (schema) { gchar *frag1 = quote_generic(schema, '"', '"'); gchar *frag2 = quote_generic(name, '"', '"'); gchar *result = g_strconcat(frag1, ".", frag2, NULL); g_free(frag1); g_free(frag2); return result; } return quote_generic(name, '"', '"'); } /* * For backends that really do NOT support schema * returns "name" or "schema_name" */ /* static gchar* quote_schema_name_dquote_merge(const gchar* schema, const gchar *name) { if (schema) { gchar *combined = g_strconcat(schema, "_", name, NULL); gchar *result = quote_generic(combined, '"', '"'); g_free(combined); return result; } return quote_generic(name, '"', '"'); }*/ static gchar* quote_schema_name_rquotes_merge(const gchar* schema, const gchar *name) { if (schema) { gchar *combined = g_strconcat(schema, "_", name, NULL); gchar *result = quote_generic(combined, '`', '`'); g_free(combined); return result; } return quote_generic(name, '`', '`'); } static gchar* quote_with_squotes(const gchar* value) { return quote_generic(value, '\'', '\''); } MDB_DEPRECATED(char*, mdb_get_coltype_string(MdbBackend *backend, int col_type)) { static int warn_deprecated = 0; static char buf[16]; if (!warn_deprecated) { warn_deprecated = 1; fprintf(stderr, "mdb_get_coltype_string is deprecated. Use mdb_get_colbacktype_string.\n"); } if (col_type > 0x10 ) { // return NULL; snprintf(buf,sizeof(buf), "type %04x", col_type); return buf; } else return backend->types_table[col_type].name; } MDB_DEPRECATED(int, mdb_coltype_takes_length(MdbBackend *backend, int col_type)) { static int warn_deprecated = 0; if (!warn_deprecated) { warn_deprecated = 1; fprintf(stderr, "mdb_coltype_takes_length is deprecated. Use mdb_colbacktype_takes_length.\n"); } return backend->types_table[col_type].needs_length; } const MdbBackendType* mdb_get_colbacktype(const MdbColumn *col) { MdbBackend *backend = col->table->entry->mdb->default_backend; int col_type = col->col_type; if (col_type > 0x10 ) return NULL; if (col_type == MDB_LONGINT && col->is_long_auto && backend->type_autonum) return backend->type_autonum; if (col_type == MDB_DATETIME && backend->type_shortdate) { const char *format = mdb_col_get_prop(col, "Format"); if (format && !strcmp(format, "Short Date")) return backend->type_shortdate; } return &backend->types_table[col_type]; } const char * mdb_get_colbacktype_string(const MdbColumn *col) { const MdbBackendType *type = mdb_get_colbacktype(col); if (!type) { // return NULL; static char buf[16]; snprintf(buf,sizeof(buf), "type %04x", col->col_type); return buf; } return type->name; } int mdb_colbacktype_takes_length(const MdbColumn *col) { const MdbBackendType *type = mdb_get_colbacktype(col); if (!type) return 0; return type->needs_length; } MDB_DEPRECATED(void, mdb_init_backends()) { fprintf(stderr, "mdb_init_backends() is DEPRECATED and does nothing. Stop calling it.\n"); } /** * _mdb_init_backends * * Initializes the mdb_backends hash and loads the builtin backends. * Use mdb_remove_backends() to destroy this hash when done. */ MDB_CONSTRUCTOR(_mdb_init_backends) { mdb_backends = g_hash_table_new(g_str_hash, g_str_equal); mdb_register_backend("access", MDB_SHEXP_DROPTABLE|MDB_SHEXP_CST_NOTNULL|MDB_SHEXP_DEFVALUES, mdb_access_types, NULL, NULL, "Date()", "Date()", "-- That file uses encoding %s\n", "DROP TABLE %s;\n", NULL, NULL, NULL, quote_schema_name_bracket_merge); mdb_register_backend("sybase", MDB_SHEXP_DROPTABLE|MDB_SHEXP_CST_NOTNULL|MDB_SHEXP_CST_NOTEMPTY|MDB_SHEXP_COMMENTS|MDB_SHEXP_DEFVALUES, mdb_sybase_types, &mdb_sybase_shortdate_type, NULL, "getdate()", "getdate()", "-- That file uses encoding %s\n", "DROP TABLE %s;\n", "ALTER TABLE %s ADD CHECK (%s <>'');\n", "COMMENT ON COLUMN %s.%s IS %s;\n", "COMMENT ON TABLE %s IS %s;\n", quote_schema_name_dquote); mdb_register_backend("oracle", MDB_SHEXP_DROPTABLE|MDB_SHEXP_CST_NOTNULL|MDB_SHEXP_COMMENTS|MDB_SHEXP_INDEXES|MDB_SHEXP_RELATIONS|MDB_SHEXP_DEFVALUES, mdb_oracle_types, &mdb_oracle_shortdate_type, NULL, "current_date", "sysdate", "-- That file uses encoding %s\n", "DROP TABLE %s;\n", NULL, "COMMENT ON COLUMN %s.%s IS %s;\n", "COMMENT ON TABLE %s IS %s;\n", quote_schema_name_dquote); mdb_register_backend("postgres", MDB_SHEXP_DROPTABLE|MDB_SHEXP_CST_NOTNULL|MDB_SHEXP_CST_NOTEMPTY|MDB_SHEXP_COMMENTS|MDB_SHEXP_INDEXES|MDB_SHEXP_RELATIONS|MDB_SHEXP_DEFVALUES, mdb_postgres_types, &mdb_postgres_shortdate_type, &mdb_postgres_serial_type, "current_date", "now()", "SET client_encoding = '%s';\n", "DROP TABLE IF EXISTS %s;\n", "ALTER TABLE %s ADD CHECK (%s <>'');\n", "COMMENT ON COLUMN %s.%s IS %s;\n", "COMMENT ON TABLE %s IS %s;\n", quote_schema_name_dquote); mdb_register_backend("mysql", MDB_SHEXP_DROPTABLE|MDB_SHEXP_CST_NOTNULL|MDB_SHEXP_CST_NOTEMPTY|MDB_SHEXP_DEFVALUES, mdb_mysql_types, &mdb_mysql_shortdate_type, NULL, "current_date", "now()", "-- That file uses encoding %s\n", "DROP TABLE IF EXISTS %s;\n", "ALTER TABLE %s ADD CHECK (%s <>'');\n", NULL, NULL, quote_schema_name_rquotes_merge); mdb_register_backend("sqlite", MDB_SHEXP_DROPTABLE|MDB_SHEXP_RELATIONS|MDB_SHEXP_DEFVALUES, mdb_sqlite_types, NULL, NULL, "date('now')", "date('now')", "-- That file uses encoding %s\n", "DROP TABLE IF EXISTS %s;\n", NULL, NULL, NULL, quote_schema_name_rquotes_merge); atexit(_mdb_remove_backends); } void mdb_register_backend(char *backend_name, guint32 capabilities, MdbBackendType *backend_type, MdbBackendType *type_shortdate, MdbBackendType *type_autonum, const char *short_now, const char *long_now, const char *charset_statement, const char *drop_statement, const char *constaint_not_empty_statement, const char *column_comment_statement, const char *table_comment_statement, gchar* (*quote_schema_name)(const gchar*, const gchar*)) { MdbBackend *backend = (MdbBackend *) g_malloc0(sizeof(MdbBackend)); backend->capabilities = capabilities; backend->types_table = backend_type; backend->type_shortdate = type_shortdate; backend->type_autonum = type_autonum; backend->short_now = short_now; backend->long_now = long_now; backend->charset_statement = charset_statement; backend->drop_statement = drop_statement; backend->constaint_not_empty_statement = constaint_not_empty_statement; backend->column_comment_statement = column_comment_statement; backend->table_comment_statement = table_comment_statement; backend->quote_schema_name = quote_schema_name; g_hash_table_insert(mdb_backends, backend_name, backend); } MDB_DEPRECATED(void, mdb_remove_backends()) { fprintf(stderr, "mdb_remove_backends() is DEPRECATED and does nothing. Stop calling it.\n"); } /** * mdb_remove_backends * * Removes all entries from and destroys the mdb_backends hash. */ void _mdb_remove_backends() { g_hash_table_foreach_remove(mdb_backends, mdb_drop_backend, NULL); g_hash_table_destroy(mdb_backends); } static gboolean mdb_drop_backend(gpointer key, gpointer value, gpointer data) { MdbBackend *backend = (MdbBackend *)value; g_free (backend); return TRUE; } /** * mdb_set_default_backend * @mdb: Handle to open MDB database file * @backend_name: Name of the backend to set as default * * Sets the default backend of the handle @mdb to @backend_name. * * Returns: 1 if successful, 0 if unsuccessful. */ int mdb_set_default_backend(MdbHandle *mdb, const char *backend_name) { MdbBackend *backend; backend = (MdbBackend *) g_hash_table_lookup(mdb_backends, backend_name); if (backend) { mdb->default_backend = backend; g_free(mdb->backend_name); // NULL is ok mdb->backend_name = (char *) g_strdup(backend_name); is_init = 0; return 1; } else { return 0; } } /** * mdb_print_indexes * @output: Where to print the sql * @table: Table to process * @dbnamespace: Target namespace/schema name */ static void mdb_print_indexes(FILE* outfile, MdbTableDef *table, char *dbnamespace) { unsigned int i, j; char* quoted_table_name; char* index_name; char* quoted_name; MdbHandle* mdb = table->entry->mdb; MdbIndex *idx; MdbColumn *col; if (strcmp(mdb->backend_name, "postgres")) { fprintf(outfile, "-- Indexes are not implemented for %s\n\n", mdb->backend_name); return; } /* read indexes */ mdb_read_indices(table); fprintf (outfile, "-- CREATE INDEXES ...\n"); quoted_table_name = mdb->default_backend->quote_schema_name(dbnamespace, table->name); for (i=0;inum_idxs;i++) { idx = g_ptr_array_index (table->indices, i); if (idx->index_type==2) continue; index_name = malloc(strlen(table->name)+strlen(idx->name)+5+1); strcpy(index_name, table->name); if (idx->index_type==1) strcat(index_name, "_pkey"); else { strcat(index_name, "_"); strcat(index_name, idx->name); strcat(index_name, "_idx"); } quoted_name = mdb->default_backend->quote_schema_name(dbnamespace, index_name); if (idx->index_type==1) { fprintf (outfile, "ALTER TABLE %s ADD CONSTRAINT %s PRIMARY KEY (", quoted_table_name, quoted_name); } else { fprintf(outfile, "CREATE"); if (idx->flags & MDB_IDX_UNIQUE) fprintf (outfile, " UNIQUE"); fprintf(outfile, " INDEX %s ON %s (", quoted_name, quoted_table_name); } g_free(quoted_name); free(index_name); for (j=0;jnum_keys;j++) { if (j) fprintf(outfile, ", "); col=g_ptr_array_index(table->columns,idx->key_col_num[j]-1); quoted_name = mdb->default_backend->quote_schema_name(NULL, col->name); fprintf (outfile, "%s", quoted_name); if (idx->index_type!=1 && idx->key_col_order[j]) /* no DESC for primary keys */ fprintf(outfile, " DESC"); g_free(quoted_name); } fprintf (outfile, ");\n"); } fputc ('\n', outfile); g_free(quoted_table_name); } /** * mdb_get_relationships * @mdb: Handle to open MDB database file * @tablename: Name of the table to process. Process all tables if NULL. * * Generates relationships by reading the MSysRelationships table. * 'szColumn' contains the column name of the child table. * 'szObject' contains the table name of the child table. * 'szReferencedColumn' contains the column name of the parent table. * 'szReferencedObject' contains the table name of the parent table. * 'grbit' contains integrity constraints. * * Returns: a string stating that relationships are not supported for the * selected backend, or a string containing SQL commands for setting up * the relationship, tailored for the selected backend. * Returns NULL on last iteration. * The caller is responsible for freeing this string. */ static char * mdb_get_relationships(MdbHandle *mdb, const gchar *dbnamespace, const char* tablename) { unsigned int i; gchar *text = NULL; /* String to be returned */ static char *bound[5]; /* Bound values */ static MdbTableDef *table; /* Relationships table */ int backend = 0; /* Backends: 1=oracle, 2=postgres */ char *quoted_table_1, *quoted_column_1, *quoted_table_2, *quoted_column_2, *constraint_name, *quoted_constraint_name; long grbit; if (!strcmp(mdb->backend_name, "oracle")) { backend = 1; } else if (!strcmp(mdb->backend_name, "postgres")) { backend = 2; } else if (!strcmp(mdb->backend_name, "sqlite")) { backend = 3; } else { if (is_init == 0) { /* the first time through */ is_init = 1; return (char *) g_strconcat( "-- relationships are not implemented for ", mdb->backend_name, "\n", NULL); } else { /* the second time through */ is_init = 0; return NULL; } } if (is_init == 0) { table = mdb_read_table_by_name(mdb, "MSysRelationships", MDB_TABLE); if ((!table) || (table->num_rows == 0)) { fprintf(stderr, "No MSysRelationships\n"); return NULL; } mdb_read_columns(table); for (i=0;i<5;i++) { bound[i] = (char *) g_malloc0(MDB_BIND_SIZE); } mdb_bind_column_by_name(table, "szColumn", bound[0], NULL); mdb_bind_column_by_name(table, "szObject", bound[1], NULL); mdb_bind_column_by_name(table, "szReferencedColumn", bound[2], NULL); mdb_bind_column_by_name(table, "szReferencedObject", bound[3], NULL); mdb_bind_column_by_name(table, "grbit", bound[4], NULL); mdb_rewind_table(table); is_init = 1; } else { if (!table) { fprintf(stderr, "table is NULL\n"); } if (table->cur_row >= table->num_rows) { /* past the last row */ for (i=0;i<5;i++) g_free(bound[i]); is_init = 0; return NULL; } } while (1) { if (!mdb_fetch_row(table)) { for (i=0;i<5;i++) g_free(bound[i]); is_init = 0; return NULL; } if (!tablename || !strcmp(bound[1], tablename)) break; } quoted_table_1 = mdb->default_backend->quote_schema_name(dbnamespace, bound[1]); quoted_column_1 = mdb->default_backend->quote_schema_name(dbnamespace, bound[0]); quoted_table_2 = mdb->default_backend->quote_schema_name(dbnamespace, bound[3]); quoted_column_2 = mdb->default_backend->quote_schema_name(dbnamespace, bound[2]); grbit = atoi(bound[4]); constraint_name = g_strconcat(bound[1], "_", bound[0], "_fk", NULL); quoted_constraint_name = mdb->default_backend->quote_schema_name(dbnamespace, constraint_name); g_free(constraint_name); if (grbit & 0x00000002) { text = g_strconcat( "-- Relationship from ", quoted_table_1, " (", quoted_column_1, ")" " to ", quoted_table_2, "(", quoted_column_2, ")", " does not enforce integrity.\n", NULL); } else { switch (backend) { case 1: /* oracle */ case 2: /* postgres */ case 3: /* sqlite */ text = g_strconcat( "ALTER TABLE ", quoted_table_1, " ADD CONSTRAINT ", quoted_constraint_name, " FOREIGN KEY (", quoted_column_1, ")" " REFERENCES ", quoted_table_2, "(", quoted_column_2, ")", (grbit & 0x00000100) ? " ON UPDATE CASCADE" : "", (grbit & 0x00001000) ? " ON DELETE CASCADE" : "", ";\n", NULL); break; } } g_free(quoted_table_1); g_free(quoted_column_1); g_free(quoted_table_2); g_free(quoted_column_2); g_free(quoted_constraint_name); return (char *)text; } static void generate_table_schema(FILE *outfile, MdbCatalogEntry *entry, char *dbnamespace, guint32 export_options) { MdbTableDef *table; MdbHandle *mdb = entry->mdb; MdbColumn *col; unsigned int i; char* quoted_table_name; char* quoted_name; MdbProperties *props; const char *prop_value; quoted_table_name = mdb->default_backend->quote_schema_name(dbnamespace, entry->object_name); /* drop the table if it exists */ if (export_options & MDB_SHEXP_DROPTABLE) fprintf (outfile, mdb->default_backend->drop_statement, quoted_table_name); /* create the table */ fprintf (outfile, "CREATE TABLE %s\n", quoted_table_name); fprintf (outfile, " (\n"); table = mdb_read_table (entry); /* get the columns */ mdb_read_columns (table); /* loop over the columns, dumping the names and types */ for (i = 0; i < table->num_cols; i++) { col = g_ptr_array_index (table->columns, i); quoted_name = mdb->default_backend->quote_schema_name(NULL, col->name); fprintf (outfile, "\t%s\t\t\t%s", quoted_name, mdb_get_colbacktype_string (col)); g_free(quoted_name); if (mdb_colbacktype_takes_length(col)) { /* more portable version from DW patch */ if (col->col_size == 0) fputs(" (255)", outfile); else fprintf(outfile, " (%d)", col->col_size); } if (export_options & MDB_SHEXP_CST_NOTNULL) { if (col->col_type == MDB_BOOL) { /* access booleans are never null */ fputs(" NOT NULL", outfile); } else { const gchar *not_null = mdb_col_get_prop(col, "Required"); if (not_null && not_null[0]=='y') fputs(" NOT NULL", outfile); } } if (export_options & MDB_SHEXP_DEFVALUES) { int done = 0; if (col->props) { gchar *defval = g_hash_table_lookup(col->props->hash, "DefaultValue"); if (defval) { size_t def_len = strlen(defval); fputs(" DEFAULT ", outfile); /* ugly hack to detect the type */ if (defval[0]=='"' && defval[def_len-1]=='"') { /* this is a string */ gchar *output_default = malloc(def_len-1); gchar *output_default_escaped; memcpy(output_default, defval+1, def_len-2); output_default[def_len-2] = 0; output_default_escaped = quote_with_squotes(output_default); fputs(output_default_escaped, outfile); g_free(output_default_escaped); free(output_default); } else if (!strcmp(defval, "Yes")) fputs("TRUE", outfile); else if (!strcmp(defval, "No")) fputs("FALSE", outfile); else if (!strcasecmp(defval, "date()")) { if (!strcmp(mdb_col_get_prop(col, "Format"), "Short Date")) fputs(mdb->default_backend->short_now, outfile); else fputs(mdb->default_backend->long_now, outfile); } else fputs(defval, outfile); done = 1; } } if (!done && col->col_type == MDB_BOOL) /* access booleans are false by default */ fputs(" DEFAULT FALSE", outfile); } if (i < table->num_cols - 1) fputs(", \n", outfile); else fputs("\n", outfile); } /* for */ fputs(");\n", outfile); /* Add the constraints on columns */ for (i = 0; i < table->num_cols; i++) { col = g_ptr_array_index (table->columns, i); props = col->props; if (!props) continue; quoted_name = mdb->default_backend->quote_schema_name(NULL, col->name); if (export_options & MDB_SHEXP_CST_NOTEMPTY) { prop_value = mdb_col_get_prop(col, "AllowZeroLength"); if (prop_value && prop_value[0]=='n') fprintf(outfile, mdb->default_backend->constaint_not_empty_statement, quoted_table_name, quoted_name); } if (export_options & MDB_SHEXP_COMMENTS) { prop_value = mdb_col_get_prop(col, "Description"); if (prop_value) { char *comment = quote_with_squotes(prop_value); fprintf(outfile, mdb->default_backend->column_comment_statement, quoted_table_name, quoted_name, comment); g_free(comment); } } g_free(quoted_name); } /* Add the comments on table */ if (export_options & MDB_SHEXP_COMMENTS) { prop_value = mdb_table_get_prop(table, "Description"); if (prop_value) { char *comment = quote_with_squotes(prop_value); fprintf(outfile, mdb->default_backend->table_comment_statement, quoted_table_name, comment); g_free(comment); } } fputc('\n', outfile); if (export_options & MDB_SHEXP_INDEXES) // prints all the indexes of that table mdb_print_indexes(outfile, table, dbnamespace); g_free(quoted_table_name); mdb_free_tabledef (table); } void mdb_print_schema(MdbHandle *mdb, FILE *outfile, char *tabname, char *dbnamespace, guint32 export_options) { unsigned int i; char *the_relation; MdbCatalogEntry *entry; const char *charset; /* clear unsupported options */ export_options &= mdb->default_backend->capabilities; /* Print out a little message to show that this came from mdb-tools. I like to know how something is generated. DW */ fputs("-- ----------------------------------------------------------\n" "-- MDB Tools - A library for reading MS Access database files\n" "-- Copyright (C) 2000-2011 Brian Bruns and others.\n" "-- Files in libmdb are licensed under LGPL and the utilities under\n" "-- the GPL, see COPYING.LIB and COPYING files respectively.\n" "-- Check out http://mdbtools.sourceforge.net\n" "-- ----------------------------------------------------------\n\n", outfile); charset = mdb_target_charset(mdb); if (charset) { fprintf(outfile, mdb->default_backend->charset_statement, charset); fputc('\n', outfile); } for (i=0; i < mdb->num_catalog; i++) { entry = g_ptr_array_index (mdb->catalog, i); if (entry->object_type == MDB_TABLE) { if ((tabname && !strcmp(entry->object_name, tabname)) || (!tabname && mdb_is_user_table(entry))) { generate_table_schema(outfile, entry, dbnamespace, export_options); } } } fprintf (outfile, "\n"); if (export_options & MDB_SHEXP_RELATIONS) { fputs ("-- CREATE Relationships ...\n", outfile); while ((the_relation=mdb_get_relationships(mdb, dbnamespace, tabname)) != NULL) { fputs(the_relation, outfile); g_free(the_relation); } } } #endif mdbtools-0.7.1/src/libmdb/catalog.c000066400000000000000000000107011222645741400171460ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "mdbtools.h" #ifdef DMALLOC #include "dmalloc.h" #endif char * mdb_get_objtype_string(int obj_type) { static char *type_name[] = {"Form", "Table", "Macro", "System Table", "Report", "Query", "Linked Table", "Module", "Relationship", "Unknown 0x09", "User Info", "Database" }; if (obj_type > 11) { return NULL; } else { return type_name[obj_type]; } } void mdb_free_catalog(MdbHandle *mdb) { unsigned int i, j; MdbCatalogEntry *entry; if ((!mdb) || (!mdb->catalog)) return; for (i=0; icatalog->len; i++) { entry = (MdbCatalogEntry *)g_ptr_array_index(mdb->catalog, i); if (entry) { if (entry->props) { for (j=0; jprops->len; j++) mdb_free_props(g_array_index(entry->props, MdbProperties*, j)); g_array_free(entry->props, TRUE); } g_free(entry); } } g_ptr_array_free(mdb->catalog, TRUE); mdb->catalog = NULL; } GPtrArray *mdb_read_catalog (MdbHandle *mdb, int objtype) { MdbCatalogEntry *entry, msysobj; MdbTableDef *table; char obj_id[256]; char obj_name[MDB_MAX_OBJ_NAME]; char obj_type[256]; char obj_flags[256]; char obj_props[MDB_BIND_SIZE]; int type; unsigned int i; MdbColumn *col_props; int kkd_size_ole; if (!mdb) return NULL; if (mdb->catalog) mdb_free_catalog(mdb); mdb->catalog = g_ptr_array_new(); mdb->num_catalog = 0; /* dummy up a catalog entry so we may read the table def */ memset(&msysobj, 0, sizeof(MdbCatalogEntry)); msysobj.mdb = mdb; msysobj.object_type = MDB_TABLE; msysobj.table_pg = 2; strcpy(msysobj.object_name, "MSysObjects"); /* mdb_table_dump(&msysobj); */ table = mdb_read_table(&msysobj); if (!table) return NULL; mdb_read_columns(table); mdb_bind_column_by_name(table, "Id", obj_id, NULL); mdb_bind_column_by_name(table, "Name", obj_name, NULL); mdb_bind_column_by_name(table, "Type", obj_type, NULL); mdb_bind_column_by_name(table, "Flags", obj_flags, NULL); i = mdb_bind_column_by_name(table, "LvProp", obj_props, &kkd_size_ole); col_props = g_ptr_array_index(table->columns, i-1); mdb_rewind_table(table); while (mdb_fetch_row(table)) { type = atoi(obj_type); if (objtype==MDB_ANY || type == objtype) { //fprintf(stderr, "obj_id: %10ld objtype: %-3d (0x%04x) obj_name: %s\n", // (atol(obj_id) & 0x00FFFFFF), type, type, obj_name); entry = (MdbCatalogEntry *) g_malloc0(sizeof(MdbCatalogEntry)); entry->mdb = mdb; strcpy(entry->object_name, obj_name); entry->object_type = (type & 0x7F); entry->table_pg = atol(obj_id) & 0x00FFFFFF; entry->flags = atol(obj_flags); mdb->num_catalog++; g_ptr_array_add(mdb->catalog, entry); if (kkd_size_ole) { size_t kkd_len; void *kkd = mdb_ole_read_full(mdb, col_props, &kkd_len); //mdb_buffer_dump(kkd, 0, kkd_len); entry->props = mdb_kkd_to_props(mdb, kkd, kkd_len); free(kkd); } } } //mdb_dump_catalog(mdb, MDB_TABLE); mdb_free_tabledef(table); return mdb->catalog; } MdbCatalogEntry * mdb_get_catalogentry_by_name(MdbHandle *mdb, const gchar* name) { unsigned int i; MdbCatalogEntry *entry; for (i=0; inum_catalog; i++) { entry = g_ptr_array_index(mdb->catalog, i); if (!strcasecmp(entry->object_name, name)) return entry; } return NULL; } void mdb_dump_catalog(MdbHandle *mdb, int obj_type) { unsigned int i; MdbCatalogEntry *entry; mdb_read_catalog(mdb, obj_type); for (i=0;inum_catalog;i++) { entry = g_ptr_array_index(mdb->catalog,i); if (obj_type==MDB_ANY || entry->object_type==obj_type) { printf("Type: %-12s Name: %-48s Page: %06lx\n", mdb_get_objtype_string(entry->object_type), entry->object_name, entry->table_pg); } } return; } mdbtools-0.7.1/src/libmdb/data.c000066400000000000000000000611531222645741400164540ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "mdbtools.h" #ifdef DMALLOC #include "dmalloc.h" #endif #define OFFSET_MASK 0x1fff char *mdb_money_to_string(MdbHandle *mdb, int start); char *mdb_numeric_to_string(MdbHandle *mdb, int start, int prec, int scale); static int _mdb_attempt_bind(MdbHandle *mdb, MdbColumn *col, unsigned char isnull, int offset, int len); static char *mdb_date_to_string(MdbHandle *mdb, int start); #ifdef MDB_COPY_OLE static size_t mdb_copy_ole(MdbHandle *mdb, void *dest, int start, int size); #endif static char date_fmt[64] = "%x %X"; void mdb_set_date_fmt(const char *fmt) { date_fmt[63] = 0; strncpy(date_fmt, fmt, 63); } void mdb_bind_column(MdbTableDef *table, int col_num, void *bind_ptr, int *len_ptr) { MdbColumn *col; /* ** the column arrary is 0 based, so decrement to get 1 based parameter */ col=g_ptr_array_index(table->columns, col_num - 1); if (bind_ptr) col->bind_ptr = bind_ptr; if (len_ptr) col->len_ptr = len_ptr; } int mdb_bind_column_by_name(MdbTableDef *table, gchar *col_name, void *bind_ptr, int *len_ptr) { unsigned int i; int col_num = -1; MdbColumn *col; for (i=0;inum_cols;i++) { col=g_ptr_array_index(table->columns,i); if (!strcasecmp(col->name,col_name)) { col_num = i + 1; if (bind_ptr) col->bind_ptr = bind_ptr; if (len_ptr) col->len_ptr = len_ptr; break; } } return col_num; } /** * mdb_find_pg_row * @mdb: Database file handle * @pg_row: Lower byte contains the row number, the upper three contain page * @buf: Pointer for returning a pointer to the page * @off: Pointer for returning an offset to the row * @len: Pointer for returning the length of the row * * Returns: 0 on success. 1 on failure. */ int mdb_find_pg_row(MdbHandle *mdb, int pg_row, void **buf, int *off, size_t *len) { unsigned int pg = pg_row >> 8; unsigned int row = pg_row & 0xff; if (mdb_read_alt_pg(mdb, pg) != mdb->fmt->pg_size) return 1; mdb_swap_pgbuf(mdb); mdb_find_row(mdb, row, off, len); mdb_swap_pgbuf(mdb); *buf = mdb->alt_pg_buf; return 0; } int mdb_find_row(MdbHandle *mdb, int row, int *start, size_t *len) { int rco = mdb->fmt->row_count_offset; int next_start; if (row > 1000) return -1; *start = mdb_get_int16(mdb->pg_buf, rco + 2 + row*2); next_start = (row == 0) ? mdb->fmt->pg_size : mdb_get_int16(mdb->pg_buf, rco + row*2) & OFFSET_MASK; *len = next_start - (*start & OFFSET_MASK); return 0; } int mdb_find_end_of_row(MdbHandle *mdb, int row) { int rco = mdb->fmt->row_count_offset; int row_end; #if 1 if (row > 1000) return -1; row_end = (row == 0) ? mdb->fmt->pg_size : mdb_get_int16(mdb->pg_buf, rco + row*2) & OFFSET_MASK; #else /* Search the previous "row start" values for the first non-'lookupflag' * one. If we don't find one, then the end of the page is the correct * value. */ int i, row_start; if (row > 1000) return -1; /* if lookupflag is not set, it's good (deleteflag is ok) */ for (i = row; i > 0; i--) { row_start = mdb_get_int16(mdb->pg_buf, (rco + i*2)); if (!(row_start & 0x8000)) { break; } } row_end = (i == 0) ? mdb->fmt->pg_size : row_start & OFFSET_MASK; #endif return row_end - 1; } int mdb_is_null(unsigned char *null_mask, int col_num) { int byte_num = (col_num - 1) / 8; int bit_num = (col_num - 1) % 8; if ((1 << bit_num) & null_mask[byte_num]) { return 0; } else { return 1; } } /* bool has to be handled specially because it uses the null bit to store its ** value*/ static size_t mdb_xfer_bound_bool(MdbHandle *mdb, MdbColumn *col, int value) { col->cur_value_len = value; if (col->bind_ptr) { strcpy(col->bind_ptr, value ? "0" : "1"); } if (col->len_ptr) { *col->len_ptr = 1; } return 1; } static size_t mdb_xfer_bound_ole(MdbHandle *mdb, int start, MdbColumn *col, int len) { size_t ret = 0; if (len) { col->cur_value_start = start; col->cur_value_len = len; } else { col->cur_value_start = 0; col->cur_value_len = 0; } #ifdef MDB_COPY_OLE if (col->bind_ptr || col->len_ptr) { ret = mdb_copy_ole(mdb, col->bind_ptr, start, len); } #else if (col->bind_ptr) { memcpy(col->bind_ptr, mdb->pg_buf + start, MDB_MEMO_OVERHEAD); } ret = MDB_MEMO_OVERHEAD; #endif if (col->len_ptr) { *col->len_ptr = ret; } return ret; } static size_t mdb_xfer_bound_data(MdbHandle *mdb, int start, MdbColumn *col, int len) { int ret; //if (!strcmp("Name",col->name)) { //printf("start %d %d\n",start, len); //} if (len) { col->cur_value_start = start; col->cur_value_len = len; } else { col->cur_value_start = 0; col->cur_value_len = 0; } if (col->bind_ptr) { if (!len) { strcpy(col->bind_ptr, ""); } else { //fprintf(stdout,"len %d size %d\n",len, col->col_size); char *str; if (col->col_type == MDB_NUMERIC) { str = mdb_numeric_to_string(mdb, start, col->col_prec, col->col_scale); } else { str = mdb_col_to_string(mdb, mdb->pg_buf, start, col->col_type, len); } strcpy(col->bind_ptr, str); g_free(str); } ret = strlen(col->bind_ptr); if (col->len_ptr) { *col->len_ptr = ret; } return ret; } return 0; } int mdb_read_row(MdbTableDef *table, unsigned int row) { MdbHandle *mdb = table->entry->mdb; MdbColumn *col; unsigned int i; int row_start; size_t row_size; int delflag, lookupflag; MdbField fields[256]; int num_fields; if (table->num_rows == 0) return 0; if (mdb_find_row(mdb, row, &row_start, &row_size)) { fprintf(stderr, "warning: mdb_find_row failed."); return 0; } delflag = lookupflag = 0; if (row_start & 0x8000) lookupflag++; if (row_start & 0x4000) delflag++; row_start &= OFFSET_MASK; /* remove flags */ #if MDB_DEBUG fprintf(stdout,"Row %d bytes %d to %d %s %s\n", row, row_start, row_start + row_size - 1, lookupflag ? "[lookup]" : "", delflag ? "[delflag]" : ""); #endif if (!table->noskip_del && delflag) { return 0; } num_fields = mdb_crack_row(table, row_start, row_start + row_size - 1, fields); if (!mdb_test_sargs(table, fields, num_fields)) return 0; #if MDB_DEBUG fprintf(stdout,"sarg test passed row %d \n", row); #endif #if MDB_DEBUG mdb_buffer_dump(mdb->pg_buf, row_start, row_size); #endif /* take advantage of mdb_crack_row() to clean up binding */ /* use num_cols instead of num_fields -- bsb 03/04/02 */ for (i = 0; i < table->num_cols; i++) { col = g_ptr_array_index(table->columns,fields[i].colnum); _mdb_attempt_bind(mdb, col, fields[i].is_null, fields[i].start, fields[i].siz); } return 1; } static int _mdb_attempt_bind(MdbHandle *mdb, MdbColumn *col, unsigned char isnull, int offset, int len) { if (col->col_type == MDB_BOOL) { mdb_xfer_bound_bool(mdb, col, isnull); } else if (isnull) { mdb_xfer_bound_data(mdb, 0, col, 0); } else if (col->col_type == MDB_OLE) { mdb_xfer_bound_ole(mdb, offset, col, len); } else { //if (!mdb_test_sargs(mdb, col, offset, len)) { //return 0; //} mdb_xfer_bound_data(mdb, offset, col, len); } return 1; } /* Read next data page into mdb->pg_buf */ int mdb_read_next_dpg(MdbTableDef *table) { MdbCatalogEntry *entry = table->entry; MdbHandle *mdb = entry->mdb; int next_pg; #ifndef SLOW_READ while (1) { next_pg = mdb_map_find_next(mdb, table->usage_map, table->map_sz, table->cur_phys_pg); if (next_pg < 0) break; /* unknow map type: goto fallback */ if (!next_pg) return 0; if (!mdb_read_pg(mdb, next_pg)) { fprintf(stderr, "error: reading page %d failed.\n", next_pg); return 0; } table->cur_phys_pg = next_pg; if (mdb->pg_buf[0]==MDB_PAGE_DATA && mdb_get_int32(mdb->pg_buf, 4)==entry->table_pg) return table->cur_phys_pg; /* On rare occasion, mdb_map_find_next will return a wrong page */ /* Found in a big file, over 4,000,000 records */ fprintf(stderr, "warning: page %d from map doesn't match: Type=%d, buf[4..7]=%ld Expected table_pg=%ld\n", next_pg, mdb->pg_buf[0], mdb_get_int32(mdb->pg_buf, 4), entry->table_pg); } fprintf(stderr, "Warning: defaulting to brute force read\n"); #endif /* can't do a fast read, go back to the old way */ do { if (!mdb_read_pg(mdb, table->cur_phys_pg++)) return 0; } while (mdb->pg_buf[0]!=MDB_PAGE_DATA || mdb_get_int32(mdb->pg_buf, 4)!=entry->table_pg); /* fprintf(stderr,"returning new page %ld\n", table->cur_phys_pg); */ return table->cur_phys_pg; } int mdb_rewind_table(MdbTableDef *table) { table->cur_pg_num=0; table->cur_phys_pg=0; table->cur_row=0; return 0; } int mdb_fetch_row(MdbTableDef *table) { MdbHandle *mdb = table->entry->mdb; MdbFormatConstants *fmt = mdb->fmt; unsigned int rows; int rc; guint32 pg; if (table->num_rows==0) return 0; /* initialize */ if (!table->cur_pg_num) { table->cur_pg_num=1; table->cur_row=0; if ((!table->is_temp_table)&&(table->strategy!=MDB_INDEX_SCAN)) if (!mdb_read_next_dpg(table)) return 0; } do { if (table->is_temp_table) { GPtrArray *pages = table->temp_table_pages; rows = mdb_get_int16( g_ptr_array_index(pages, table->cur_pg_num-1), fmt->row_count_offset); if (table->cur_row >= rows) { table->cur_row = 0; table->cur_pg_num++; if (table->cur_pg_num > pages->len) return 0; } memcpy(mdb->pg_buf, g_ptr_array_index(pages, table->cur_pg_num-1), fmt->pg_size); } else if (table->strategy==MDB_INDEX_SCAN) { if (!mdb_index_find_next(table->mdbidx, table->scan_idx, table->chain, &pg, (guint16 *) &(table->cur_row))) { mdb_index_scan_free(table); return 0; } mdb_read_pg(mdb, pg); } else { rows = mdb_get_int16(mdb->pg_buf,fmt->row_count_offset); /* if at end of page, find a new data page */ if (table->cur_row >= rows) { table->cur_row=0; if (!mdb_read_next_dpg(table)) { return 0; } } } /* printf("page %d row %d\n",table->cur_phys_pg, table->cur_row); */ rc = mdb_read_row(table, table->cur_row); table->cur_row++; } while (!rc); return 1; } void mdb_data_dump(MdbTableDef *table) { unsigned int i; char *bound_values[MDB_MAX_COLS]; for (i=0;inum_cols;i++) { bound_values[i] = (char *) g_malloc(256); mdb_bind_column(table, i+1, bound_values[i], NULL); } mdb_rewind_table(table); while (mdb_fetch_row(table)) { for (i=0;inum_cols;i++) { fprintf(stdout, "column %d is %s\n", i+1, bound_values[i]); } } for (i=0;inum_cols;i++) { g_free(bound_values[i]); } } int mdb_is_fixed_col(MdbColumn *col) { return col->is_fixed; } #if 0 static char *mdb_data_to_hex(MdbHandle *mdb, char *text, int start, int size) { int i; for (i=start; ipg_buf[i]); } text[(i-start)*2]='\0'; return text; } #endif /* * ole_ptr should point to the original blob value of the field. * If omited, there will be no multi-page check to that the caller is * responsible for not calling this function. Then, it doesn't have to * preserve the original value. */ size_t mdb_ole_read_next(MdbHandle *mdb, MdbColumn *col, void *ole_ptr) { guint32 ole_len; void *buf; int row_start; size_t len; if (ole_ptr) { ole_len = mdb_get_int32(ole_ptr, 0); mdb_debug(MDB_DEBUG_OLE,"ole len = %d ole flags = %02x", ole_len & 0x00ffffff, ole_len >> 24); if ((ole_len & 0x80000000) || (ole_len & 0x40000000)) /* inline or single-page fields don't have a next */ return 0; } mdb_debug(MDB_DEBUG_OLE, "pg_row %d", col->cur_blob_pg_row); if (!col->cur_blob_pg_row) return 0; /* we are done */ if (mdb_find_pg_row(mdb, col->cur_blob_pg_row, &buf, &row_start, &len)) { return 0; } mdb_debug(MDB_DEBUG_OLE,"start %d len %d", row_start, len); if (col->bind_ptr) memcpy(col->bind_ptr, buf + row_start + 4, len - 4); col->cur_blob_pg_row = mdb_get_int32(buf, row_start); return len - 4; } size_t mdb_ole_read(MdbHandle *mdb, MdbColumn *col, void *ole_ptr, int chunk_size) { guint32 ole_len; void *buf; int row_start; size_t len; ole_len = mdb_get_int32(ole_ptr, 0); mdb_debug(MDB_DEBUG_OLE,"ole len = %d ole flags = %02x", ole_len & 0x00ffffff, ole_len >> 24); col->chunk_size = chunk_size; if (ole_len & 0x80000000) { /* inline ole field, if we can satisfy it, then do it */ len = col->cur_value_len - MDB_MEMO_OVERHEAD; if (chunk_size >= len) { if (col->bind_ptr) memcpy(col->bind_ptr, &mdb->pg_buf[col->cur_value_start + MDB_MEMO_OVERHEAD], len); return len; } else { return 0; } } else if (ole_len & 0x40000000) { col->cur_blob_pg_row = mdb_get_int32(ole_ptr, 4); mdb_debug(MDB_DEBUG_OLE,"ole row = %d ole pg = %ld", col->cur_blob_pg_row & 0xff, col->cur_blob_pg_row >> 8); if (mdb_find_pg_row(mdb, col->cur_blob_pg_row, &buf, &row_start, &len)) { return 0; } mdb_debug(MDB_DEBUG_OLE,"start %d len %d", row_start, len); if (col->bind_ptr) { memcpy(col->bind_ptr, buf + row_start, len); if (mdb_get_option(MDB_DEBUG_OLE)) mdb_buffer_dump(col->bind_ptr, 0, 16); } return len; } else if ((ole_len & 0xff000000) == 0) { col->cur_blob_pg_row = mdb_get_int32(ole_ptr, 4); mdb_debug(MDB_DEBUG_OLE,"ole row = %d ole pg = %ld", col->cur_blob_pg_row & 0xff, col->cur_blob_pg_row >> 8); if (mdb_find_pg_row(mdb, col->cur_blob_pg_row, &buf, &row_start, &len)) { return 0; } mdb_debug(MDB_DEBUG_OLE,"start %d len %d", row_start, len); if (col->bind_ptr) memcpy(col->bind_ptr, buf + row_start + 4, len - 4); col->cur_blob_pg_row = mdb_get_int32(buf, row_start); mdb_debug(MDB_DEBUG_OLE, "next pg_row %d", col->cur_blob_pg_row); return len - 4; } else { fprintf(stderr,"Unhandled ole field flags = %02x\n", ole_len >> 24); return 0; } } /* * mdb_ole_read_full calls mdb_ole_read then loop over mdb_ole_read_next as much as necessary. * returns the result in a big buffer. * The call must free it. * Note that this function is not indempotent: It may be called only once per column after each bind. */ void* mdb_ole_read_full(MdbHandle *mdb, MdbColumn *col, size_t *size) { char ole_ptr[MDB_MEMO_OVERHEAD]; char *result = malloc(MDB_BIND_SIZE); size_t result_buffer_size = MDB_BIND_SIZE; size_t len, pos; memcpy(ole_ptr, col->bind_ptr, MDB_MEMO_OVERHEAD); len = mdb_ole_read(mdb, col, ole_ptr, MDB_BIND_SIZE); memcpy(result, col->bind_ptr, len); pos = len; while ((len = mdb_ole_read_next(mdb, col, ole_ptr))) { if (pos+len >= result_buffer_size) { result_buffer_size += MDB_BIND_SIZE; result = realloc(result, result_buffer_size); } memcpy(result + pos, col->bind_ptr, len); pos += len; } if (size) *size = pos; return result; } #ifdef MDB_COPY_OLE static size_t mdb_copy_ole(MdbHandle *mdb, void *dest, int start, int size) { guint32 ole_len; gint32 row_start, pg_row; size_t len; void *buf, *pg_buf = mdb->pg_buf; if (size> 8); if (mdb_find_pg_row(mdb, pg_row, &buf, &row_start, &len)) { return 0; } mdb_debug(MDB_DEBUG_OLE,"row num %d start %d len %d", pg_row & 0xff, row_start, len); if (dest) memcpy(dest, buf + row_start, len); return len; } else if ((ole_len & 0xff000000) == 0) { // assume all flags in MSB /* multi-page */ int cur = 0; pg_row = mdb_get_int32(pg_buf, start+4); do { mdb_debug(MDB_DEBUG_OLE,"Reading LVAL page %06x", pg_row >> 8); if (mdb_find_pg_row(mdb,pg_row,&buf,&row_start,&len)) { return 0; } mdb_debug(MDB_DEBUG_OLE,"row num %d start %d len %d", pg_row & 0xff, row_start, len); if (dest) memcpy(dest+cur, buf + row_start + 4, len - 4); cur += len - 4; /* find next lval page */ pg_row = mdb_get_int32(buf, row_start); } while ((pg_row >> 8)); return cur; } else { fprintf(stderr, "Unhandled ole field flags = %02x\n", ole_len >> 24); return 0; } } #endif static char *mdb_memo_to_string(MdbHandle *mdb, int start, int size) { guint32 memo_len; gint32 row_start, pg_row; size_t len; void *buf, *pg_buf = mdb->pg_buf; char *text = (char *) g_malloc(MDB_BIND_SIZE); if (size> 8); #endif if (mdb_find_pg_row(mdb, pg_row, &buf, &row_start, &len)) { strcpy(text, ""); return text; } #if MDB_DEBUG printf("row num %d start %d len %d\n", pg_row & 0xff, row_start, len); mdb_buffer_dump(buf, row_start, len); #endif mdb_unicode2ascii(mdb, buf + row_start, len, text, MDB_BIND_SIZE); return text; } else if ((memo_len & 0xff000000) == 0) { // assume all flags in MSB /* multi-page memo field */ guint32 tmpoff = 0; char *tmp; tmp = (char *) g_malloc(memo_len); pg_row = mdb_get_int32(pg_buf, start+4); do { #if MDB_DEBUG printf("Reading LVAL page %06x\n", pg_row >> 8); #endif if (mdb_find_pg_row(mdb,pg_row,&buf,&row_start,&len)) { g_free(tmp); strcpy(text, ""); return text; } #if MDB_DEBUG printf("row num %d start %d len %d\n", pg_row & 0xff, row_start, len); #endif if (tmpoff + len - 4 > memo_len) { break; } memcpy(tmp + tmpoff, buf + row_start + 4, len - 4); tmpoff += len - 4; } while (( pg_row = mdb_get_int32(buf, row_start) )); if (tmpoff < memo_len) { fprintf(stderr, "Warning: incorrect memo length\n"); } mdb_unicode2ascii(mdb, tmp, tmpoff, text, MDB_BIND_SIZE); g_free(tmp); return text; } else { fprintf(stderr, "Unhandled memo field flags = %02x\n", memo_len >> 24); strcpy(text, ""); return text; } } #if 0 static int trim_trailing_zeros(char * buff) { char *p; int n = strlen(buff); /* Don't need to trim strings with no decimal portion */ if(!strchr(buff,'.')) return 0; /* Trim the zeros */ p = buff + n - 1; while (p >= buff && *p == '0') *p-- = '\0'; /* If a decimal sign is left at the end, remove it too */ if (*p == '.') *p = '\0'; return 0; } #endif /* Date/Time is stored as a double, where the whole part is the days from 12/30/1899 and the fractional part is the fractional part of one day. */ void mdb_date_to_tm(double td, struct tm *t) { long int day, time; int yr, q; int *cal; int noleap_cal[] = {0,31,59,90,120,151,181,212,243,273,304,334,365}; int leap_cal[] = {0,31,60,91,121,152,182,213,244,274,305,335,366}; day = (long int)(td); time = (long int)(fabs(td - day) * 86400.0 + 0.5); t->tm_hour = time / 3600; t->tm_min = (time / 60) % 60; t->tm_sec = time % 60; t->tm_year = 1 - 1900; day += 693593; /* Days from 1/1/1 to 12/31/1899 */ t->tm_wday = (day+1) % 7; q = day / 146097; /* 146097 days in 400 years */ t->tm_year += 400 * q; day -= q * 146097; q = day / 36524; /* 36524 days in 100 years */ if (q > 3) q = 3; t->tm_year += 100 * q; day -= q * 36524; q = day / 1461; /* 1461 days in 4 years */ t->tm_year += 4 * q; day -= q * 1461; q = day / 365; /* 365 days in 1 year */ if (q > 3) q = 3; t->tm_year += q; day -= q * 365; yr = t->tm_year + 1900; cal = ((yr)%4==0 && ((yr)%100!=0 || (yr)%400==0)) ? leap_cal : noleap_cal; for (t->tm_mon=0; t->tm_mon<12; t->tm_mon++) { if (day < cal[t->tm_mon+1]) break; } t->tm_mday = day - cal[t->tm_mon] + 1; t->tm_yday = day; t->tm_isdst = -1; } static char * mdb_date_to_string(MdbHandle *mdb, int start) { struct tm t; char *text = (char *) g_malloc(MDB_BIND_SIZE); double td = mdb_get_double(mdb->pg_buf, start); mdb_date_to_tm(td, &t); strftime(text, MDB_BIND_SIZE, date_fmt, &t); return text; } static char * mdb_uuid_to_string(MdbHandle *mdb, int start) { char *text = NULL; unsigned short uuid1, uuid2, uuid3, uuid4, uuid5, uuid6, uuid7, uuid8; uuid1 = mdb_get_int16(mdb->pg_buf, start); uuid2 = mdb_get_int16(mdb->pg_buf, start + 2); uuid3 = mdb_get_int16(mdb->pg_buf, start + 4); uuid4 = mdb_get_int16(mdb->pg_buf, start + 6); uuid5 = mdb_get_int16(mdb->pg_buf, start + 8); uuid6 = mdb_get_int16(mdb->pg_buf, start + 10); uuid7 = mdb_get_int16(mdb->pg_buf, start + 12); uuid8 = mdb_get_int16(mdb->pg_buf, start + 14); text = g_strdup_printf("{%04x%04x-%04x-%04x-%04x-%04x%04x%04x}", uuid1, uuid2, uuid3, uuid4, uuid5, uuid6, uuid7, uuid8); return text; } #if 0 int floor_log10(double f, int is_single) { unsigned int i; double y = 10.0; if (f < 0.0) f = -f; if ((f == 0.0) || (f == 1.0) || isinf(f)) { return 0; } else if (f < 1.0) { if (is_single) { /* The intermediate value p is necessary to prevent * promotion of the comparison to type double */ float p; for (i=1; (p = f * y) < 1.0; i++) y *= 10.0; } else { for (i=1; f * y < 1.0; i++) y *= 10.0; } return -(int)i; } else { /* (x > 1.0) */ for (i=0; f >= y; i++) y *= 10.0; return (int)i; } } #endif char *mdb_col_to_string(MdbHandle *mdb, void *buf, int start, int datatype, int size) { char *text = NULL; float tf; double td; switch (datatype) { case MDB_BOOL: /* shouldn't happen. bools are handled specially ** by mdb_xfer_bound_bool() */ break; case MDB_BYTE: text = g_strdup_printf("%d", mdb_get_byte(buf, start)); break; case MDB_INT: text = g_strdup_printf("%hd", (short)mdb_get_int16(buf, start)); break; case MDB_LONGINT: case MDB_COMPLEX: text = g_strdup_printf("%ld", mdb_get_int32(buf, start)); break; case MDB_FLOAT: tf = mdb_get_single(buf, start); text = g_strdup_printf("%.8e", tf); break; case MDB_DOUBLE: td = mdb_get_double(buf, start); text = g_strdup_printf("%.16e", td); break; case MDB_BINARY: if (size<0) { text = g_strdup(""); } else { text = g_malloc(size); memcpy((char*)buf+start, text, size); } break; case MDB_TEXT: if (size<0) { text = g_strdup(""); } else { text = (char *) g_malloc(MDB_BIND_SIZE); mdb_unicode2ascii(mdb, buf + start, size, text, MDB_BIND_SIZE); } break; case MDB_DATETIME: text = mdb_date_to_string(mdb, start); break; case MDB_MEMO: text = mdb_memo_to_string(mdb, start, size); break; case MDB_MONEY: text = mdb_money_to_string(mdb, start); case MDB_NUMERIC: break; case MDB_REPID: text = mdb_uuid_to_string(mdb, start); break; default: text = g_strdup(""); break; } return text; } int mdb_col_disp_size(MdbColumn *col) { switch (col->col_type) { case MDB_BOOL: return 1; break; case MDB_BYTE: return 4; break; case MDB_INT: return 6; break; case MDB_LONGINT: case MDB_COMPLEX: return 11; break; case MDB_FLOAT: return 10; break; case MDB_DOUBLE: return 10; break; case MDB_TEXT: return col->col_size; break; case MDB_DATETIME: return 20; break; case MDB_MEMO: return 64000; break; case MDB_MONEY: return 21; break; } return 0; } int mdb_col_fixed_size(MdbColumn *col) { switch (col->col_type) { case MDB_BOOL: return 1; break; case MDB_BYTE: return -1; break; case MDB_INT: return 2; break; case MDB_LONGINT: case MDB_COMPLEX: return 4; break; case MDB_FLOAT: return 4; break; case MDB_DOUBLE: return 8; break; case MDB_TEXT: return -1; break; case MDB_DATETIME: return 4; break; case MDB_BINARY: return -1; break; case MDB_MEMO: return -1; break; case MDB_MONEY: return 8; break; } return 0; } mdbtools-0.7.1/src/libmdb/dump.c000066400000000000000000000030441222645741400165030ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database files * Copyright (C) 2000-2011 Brian Bruns and others * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #ifdef DMALLOC #include "dmalloc.h" #endif void mdb_buffer_dump(const void* buf, int start, size_t len) { char asc[20]; int j, k; memset(asc, 0, sizeof(asc)); k = 0; for (j=start; j #include "mdbtools.h" #ifdef DMALLOC #include "dmalloc.h" #endif /* typedef struct { int pg_size; guint16 row_count_offset; guint16 tab_num_rows_offset; guint16 tab_num_cols_offset; guint16 tab_num_idxs_offset; guint16 tab_num_ridxs_offset; guint16 tab_usage_map_offset; guint16 tab_first_dpg_offset; guint16 tab_cols_start_offset; guint16 tab_ridx_entry_size; guint16 col_flags_offset; guint16 col_size_offset; guint16 col_num_offset; guint16 tab_col_entry_size; guint16 tab_free_map_offset; guint16 tab_col_offset_var; guint16 tab_col_offset_fixed; guint16 tab_row_col_num_offset; } MdbFormatConstants; */ MdbFormatConstants MdbJet4Constants = { 4096, 0x0c, 16, 45, 47, 51, 55, 56, 63, 12, 15, 23, 5, 25, 59, 7, 21, 9 }; MdbFormatConstants MdbJet3Constants = { 2048, 0x08, 12, 25, 27, 31, 35, 36, 43, 8, 13, 16, 1, 18, 39, 3, 14, 5 }; typedef struct _RC4_KEY { unsigned char state[256]; unsigned char x; unsigned char y; } RC4_KEY; #define swap_byte(x,y) t = *(x); *(x) = *(y); *(y) = t static ssize_t _mdb_read_pg(MdbHandle *mdb, void *pg_buf, unsigned long pg); static void RC4_set_key(RC4_KEY *key, int key_data_len, unsigned char *key_data_ptr) { unsigned char t; unsigned char index1; unsigned char index2; unsigned char* state; short counter; state = &key->state[0]; for(counter = 0; counter < 256; counter++) state[counter] = counter; key->x = 0; key->y = 0; index1 = 0; index2 = 0; for(counter = 0; counter < 256; counter++) { index2 = (key_data_ptr[index1] + state[counter] + index2) % 256; swap_byte(&state[counter], &state[index2]); index1 = (index1 + 1) % key_data_len; } } /* * this algorithm does 'encrypt in place' instead of inbuff/outbuff * note also: encryption and decryption use same routine * implementation supplied by (Adam Back) at */ static void RC4(RC4_KEY *key, int buffer_len, unsigned char * buff) { unsigned char t; unsigned char x; unsigned char y; unsigned char* state; unsigned char xorIndex; short counter; x = key->x; y = key->y; state = &key->state[0]; for(counter = 0; counter < buffer_len; counter++) { x = (x + 1) % 256; y = (state[x] + y) % 256; swap_byte(&state[x], &state[y]); xorIndex = (state[x] + state[y]) % 256; buff[counter] ^= state[xorIndex]; } key->x = x; key->y = y; } /** * mdb_find_file: * @filename: path to MDB (database) file * * Finds and returns the absolute path to an MDB file. Function will first try * to fstat file as passed, then search through the $MDBPATH if not found. * * Return value: gchar pointer to absolute path. Caller is responsible for * freeing. **/ static char *mdb_find_file(const char *file_name) { struct stat status; gchar *mdbpath, **dir, *tmpfname; unsigned int i = 0; /* try the provided file name first */ if (!stat(file_name, &status)) { char *result; result = g_strdup(file_name); if (!result) fprintf(stderr, "Can't alloc filename\n"); return result; } /* Now pull apart $MDBPATH and try those */ mdbpath = (gchar *) getenv("MDBPATH"); /* no path, can't find file */ if (!mdbpath || !strlen(mdbpath)) return NULL; dir = g_strsplit(mdbpath, ":", 0); while (dir[i]) { if (!strlen(dir[i])) continue; tmpfname = g_strconcat(dir[i++], "/", file_name, NULL); if (!stat(tmpfname, &status)) { g_strfreev(dir); return tmpfname; } g_free(tmpfname); } g_strfreev(dir); return NULL; } /** * mdb_open: * @filename: path to MDB (database) file * @flags: MDB_NOFLAGS for read-only, MDB_WRITABLE for read/write * * Opens an MDB file and returns an MdbHandle to it. MDB File may be relative * to the current directory, a full path to the file, or relative to a * component of $MDBPATH. * * Return value: pointer to MdbHandle structure. **/ MdbHandle *mdb_open(const char *filename, MdbFileFlags flags) { MdbHandle *mdb; int key[] = {0x86, 0xfb, 0xec, 0x37, 0x5d, 0x44, 0x9c, 0xfa, 0xc6, 0x5e, 0x28, 0xe6, 0x13, 0xb6}; int j, pos; int open_flags; mdb = (MdbHandle *) g_malloc0(sizeof(MdbHandle)); mdb_set_default_backend(mdb, "access"); #ifdef HAVE_ICONV mdb->iconv_in = (iconv_t)-1; mdb->iconv_out = (iconv_t)-1; #endif /* need something to bootstrap with, reassign after page 0 is read */ mdb->fmt = &MdbJet3Constants; mdb->f = (MdbFile *) g_malloc0(sizeof(MdbFile)); mdb->f->refs = 1; mdb->f->fd = -1; mdb->f->filename = mdb_find_file(filename); if (!mdb->f->filename) { fprintf(stderr, "File not found\n"); mdb_close(mdb); return NULL; } if (flags & MDB_WRITABLE) { mdb->f->writable = TRUE; open_flags = O_RDWR; } else { open_flags = O_RDONLY; } #ifdef _WIN32 open_flags |= O_BINARY; #endif mdb->f->fd = open(mdb->f->filename, open_flags); if (mdb->f->fd==-1) { fprintf(stderr,"Couldn't open file %s\n",mdb->f->filename); mdb_close(mdb); return NULL; } if (!mdb_read_pg(mdb, 0)) { fprintf(stderr,"Couldn't read first page.\n"); mdb_close(mdb); return NULL; } if (mdb->pg_buf[0] != 0) { mdb_close(mdb); return NULL; } mdb->f->jet_version = mdb_get_int32(mdb->pg_buf, 0x14); switch(mdb->f->jet_version) { case MDB_VER_JET3: mdb->fmt = &MdbJet3Constants; break; case MDB_VER_JET4: case MDB_VER_ACCDB_2007: case MDB_VER_ACCDB_2010: mdb->fmt = &MdbJet4Constants; break; default: fprintf(stderr,"Unknown Jet version.\n"); mdb_close(mdb); return NULL; } mdb->f->db_key = mdb_get_int32(mdb->pg_buf, 0x3e); /* I don't know if this value is valid for some versions? * it doesn't seem to be valid for the databases I have * * f->db_key ^= 0xe15e01b9; */ mdb->f->db_key ^= 0x4ebc8afb; /* fprintf(stderr, "Encrypted file, RC4 key seed= %d\n", mdb->f->db_key); */ if (mdb->f->db_key) { /* write is not supported for encrypted files yet */ mdb->f->writable = FALSE; /* that should be enought, but reopen the file read only just to be * sure we don't write invalid data */ close(mdb->f->fd); open_flags = O_RDONLY; #ifdef _WIN32 open_flags |= O_BINARY; #endif mdb->f->fd = open(mdb->f->filename, open_flags); if (mdb->f->fd==-1) { fprintf(stderr, "Couldn't ropen file %s in read only\n", mdb->f->filename); mdb_close(mdb); return NULL; } } /* get the db password located at 0x42 bytes into the file */ for (pos=0;pos<14;pos++) { j = mdb_get_int32(mdb->pg_buf, 0x42+pos); j ^= key[pos]; if ( j != 0) mdb->f->db_passwd[pos] = j; else mdb->f->db_passwd[pos] = '\0'; } mdb_iconv_init(mdb); return mdb; } /** * mdb_close: * @mdb: Handle to open MDB database file * * Dereferences MDB file, closes if reference count is 0, and destroys handle. * **/ void mdb_close(MdbHandle *mdb) { if (!mdb) return; mdb_free_catalog(mdb); g_free(mdb->stats); g_free(mdb->backend_name); if (mdb->f) { if (mdb->f->refs > 1) { mdb->f->refs--; } else { if (mdb->f->fd != -1) close(mdb->f->fd); g_free(mdb->f->filename); g_free(mdb->f); } } mdb_iconv_close(mdb); g_free(mdb); } /** * mdb_clone_handle: * @mdb: Handle to open MDB database file * * Clones an existing database handle. Cloned handle shares the file descriptor * but has its own page buffer, page position, and similar internal variables. * * Return value: new handle to the database. */ MdbHandle *mdb_clone_handle(MdbHandle *mdb) { MdbHandle *newmdb; MdbCatalogEntry *entry, *data; unsigned int i; newmdb = (MdbHandle *) g_memdup(mdb, sizeof(MdbHandle)); newmdb->stats = NULL; newmdb->catalog = g_ptr_array_new(); for (i=0;inum_catalog;i++) { entry = g_ptr_array_index(mdb->catalog,i); data = g_memdup(entry,sizeof(MdbCatalogEntry)); g_ptr_array_add(newmdb->catalog, data); } mdb->backend_name = NULL; if (mdb->f) { mdb->f->refs++; } mdb_iconv_init(mdb); return newmdb; } /* ** mdb_read a wrapper for read that bails if anything is wrong */ ssize_t mdb_read_pg(MdbHandle *mdb, unsigned long pg) { ssize_t len; if (pg && mdb->cur_pg == pg) return mdb->fmt->pg_size; len = _mdb_read_pg(mdb, mdb->pg_buf, pg); //fprintf(stderr, "read page %d type %02x\n", pg, mdb->pg_buf[0]); mdb->cur_pg = pg; /* kan - reset the cur_pos on a new page read */ mdb->cur_pos = 0; /* kan */ return len; } ssize_t mdb_read_alt_pg(MdbHandle *mdb, unsigned long pg) { ssize_t len; len = _mdb_read_pg(mdb, mdb->alt_pg_buf, pg); return len; } static ssize_t _mdb_read_pg(MdbHandle *mdb, void *pg_buf, unsigned long pg) { ssize_t len; struct stat status; off_t offset = pg * mdb->fmt->pg_size; fstat(mdb->f->fd, &status); if (status.st_size < offset) { fprintf(stderr,"offset %jd is beyond EOF\n",(intmax_t)offset); return 0; } if (mdb->stats && mdb->stats->collect) mdb->stats->pg_reads++; lseek(mdb->f->fd, offset, SEEK_SET); len = read(mdb->f->fd,pg_buf,mdb->fmt->pg_size); if (len==-1) { perror("read"); return 0; } else if (lenfmt->pg_size) { /* fprintf(stderr,"EOF reached %d bytes returned.\n",len, mdb->fmt->pg_size); */ return 0; } /* * unencrypt the page if necessary. * it might make sense to cache the unencrypted data blocks? */ if (pg != 0 && mdb->f->db_key != 0) { RC4_KEY rc4_key; unsigned int tmp_key = mdb->f->db_key ^ pg; RC4_set_key(&rc4_key, 4, (unsigned char *)&tmp_key); RC4(&rc4_key, mdb->fmt->pg_size, pg_buf); } return len; } void mdb_swap_pgbuf(MdbHandle *mdb) { char tmpbuf[MDB_PGSIZE]; memcpy(tmpbuf,mdb->pg_buf, MDB_PGSIZE); memcpy(mdb->pg_buf,mdb->alt_pg_buf, MDB_PGSIZE); memcpy(mdb->alt_pg_buf,tmpbuf,MDB_PGSIZE); } unsigned char mdb_get_byte(void *buf, int offset) { return ((unsigned char *)(buf))[offset]; } unsigned char mdb_pg_get_byte(MdbHandle *mdb, int offset) { if (offset < 0 || offset+1 > mdb->fmt->pg_size) return -1; mdb->cur_pos++; return mdb->pg_buf[offset]; } int mdb_get_int16(void *buf, int offset) { guint16 l; memcpy(&l, buf + offset, 2); return (int)GUINT16_FROM_LE(l); } int mdb_pg_get_int16(MdbHandle *mdb, int offset) { if (offset < 0 || offset+2 > mdb->fmt->pg_size) return -1; mdb->cur_pos+=2; return mdb_get_int16(mdb->pg_buf, offset); } long mdb_get_int32_msb(void *buf, int offset) { gint32 l; memcpy(&l, buf + offset, 4); return (long)GINT32_FROM_BE(l); } long mdb_get_int32(void *buf, int offset) { gint32 l; memcpy(&l, buf + offset, 4); return (long)GINT32_FROM_LE(l); } long mdb_pg_get_int32(MdbHandle *mdb, int offset) { if (offset <0 || offset+4 > mdb->fmt->pg_size) return -1; mdb->cur_pos+=4; return mdb_get_int32(mdb->pg_buf, offset); } float mdb_get_single(void *buf, int offset) { union {guint32 g; float f;} f; memcpy(&f, buf + offset, 4); f.g = GUINT32_FROM_LE(f.g); return f.f; } float mdb_pg_get_single(MdbHandle *mdb, int offset) { if (offset <0 || offset+4 > mdb->fmt->pg_size) return -1; mdb->cur_pos+=4; return mdb_get_single(mdb->pg_buf, offset); } double mdb_get_double(void *buf, int offset) { union {guint64 g; double d;} d; memcpy(&d, buf + offset, 8); d.g = GUINT64_FROM_LE(d.g); return d.d; } double mdb_pg_get_double(MdbHandle *mdb, int offset) { if (offset <0 || offset+8 > mdb->fmt->pg_size) return -1; mdb->cur_pos+=8; return mdb_get_double(mdb->pg_buf, offset); } int mdb_set_pos(MdbHandle *mdb, int pos) { if (pos<0 || pos >= mdb->fmt->pg_size) return 0; mdb->cur_pos=pos; return pos; } int mdb_get_pos(MdbHandle *mdb) { return mdb->cur_pos; } mdbtools-0.7.1/src/libmdb/iconv.c000066400000000000000000000132641222645741400166610ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database files * Copyright (C) 2000 Brian Bruns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "mdbtools.h" #ifdef DMALLOC #include "dmalloc.h" #endif /* * This function is used in reading text data from an MDB table. */ int mdb_unicode2ascii(MdbHandle *mdb, char *src, size_t slen, char *dest, size_t dlen) { char *tmp = NULL; size_t tlen = 0; size_t len_in, len_out; char *in_ptr, *out_ptr; if ((!src) || (!dest) || (!dlen)) return 0; /* Uncompress 'Unicode Compressed' string into tmp */ if (!IS_JET3(mdb) && (slen>=2) && ((src[0]&0xff)==0xff) && ((src[1]&0xff)==0xfe)) { unsigned int compress=1; src += 2; slen -= 2; tmp = (char *)g_malloc(slen*2); while (slen) { if (*src == 0) { compress = (compress) ? 0 : 1; src++; slen--; } else if (compress) { tmp[tlen++] = *src++; tmp[tlen++] = 0; slen--; } else if (slen >= 2){ tmp[tlen++] = *src++; tmp[tlen++] = *src++; slen-=2; } } } in_ptr = (tmp) ? tmp : src; out_ptr = dest; len_in = (tmp) ? tlen : slen; len_out = dlen; #if HAVE_ICONV //printf("1 len_in %d len_out %d\n",len_in, len_out); while (1) { iconv(mdb->iconv_in, &in_ptr, &len_in, &out_ptr, &len_out); if ((!len_in) || (errno == E2BIG)) break; /* Don't bail if impossible conversion is encountered */ in_ptr += (IS_JET3(mdb)) ? 1 : 2; len_in -= (IS_JET3(mdb)) ? 1 : 2; *out_ptr++ = '?'; len_out--; } //printf("2 len_in %d len_out %d\n",len_in, len_out); dlen -= len_out; #else if (IS_JET3(mdb)) { size_t copy_len = len_in; if (copy_len > dlen) copy_len = dlen; strncpy(out_ptr, in_ptr, copy_len); dlen = copy_len; } else { /* rough UCS-2LE to ISO-8859-1 conversion */ unsigned int i; for (i=0; iiconv_out, &in_ptr, &len_in, &out_ptr, &len_out); //printf("len_in %d len_out %d\n", len_in, len_out); dlen -= len_out; #else if (IS_JET3(mdb)) { dlen = MIN(len_in, len_out); strncpy(out_ptr, in_ptr, dlen); } else { unsigned int i; slen = MIN(len_in, len_out/2); dlen = slen*2; for (i=0; i4)) { unsigned char *tmp = g_malloc(dlen); unsigned int tptr = 0, dptr = 0; int comp = 1; tmp[tptr++] = 0xff; tmp[tptr++] = 0xfe; while((dptr < dlen) && (tptr < dlen)) { if (((dest[dptr+1]==0) && (comp==0)) || ((dest[dptr+1]!=0) && (comp==1))) { /* switch encoding mode */ tmp[tptr++] = 0; comp = (comp) ? 0 : 1; } else if (dest[dptr]==0) { /* this string cannot be compressed */ tptr = dlen; } else if (comp==1) { /* encode compressed character */ tmp[tptr++] = dest[dptr]; dptr += 2; } else if (tptr+1 < dlen) { /* encode uncompressed character */ tmp[tptr++] = dest[dptr]; tmp[tptr++] = dest[dptr+1]; dptr += 2; } else { /* could not encode uncompressed character * into single byte */ tptr = dlen; } } if (tptr < dlen) { memcpy(dest, tmp, tptr); dlen = tptr; } g_free(tmp); } return dlen; } const char* mdb_target_charset(MdbHandle *mdb) { #ifdef HAVE_ICONV const char *iconv_code = getenv("MDBICONV"); if (!iconv_code) iconv_code = "UTF-8"; return iconv_code; #else if (!IS_JET3(mdb)) return "ISO-8859-1"; return NULL; // same as input: unknown #endif } void mdb_iconv_init(MdbHandle *mdb) { const char *iconv_code; /* check environment variable */ if (!(iconv_code=getenv("MDBICONV"))) { iconv_code="UTF-8"; } #ifdef HAVE_ICONV if (!IS_JET3(mdb)) { mdb->iconv_out = iconv_open("UCS-2LE", iconv_code); mdb->iconv_in = iconv_open(iconv_code, "UCS-2LE"); } else { /* According to Microsoft Knowledge Base pages 289525 and */ /* 202427, code page info is not contained in the database */ const char *jet3_iconv_code; /* check environment variable */ if (!(jet3_iconv_code=getenv("MDB_JET3_CHARSET"))) { jet3_iconv_code="CP1252"; } mdb->iconv_out = iconv_open(jet3_iconv_code, iconv_code); mdb->iconv_in = iconv_open(iconv_code, jet3_iconv_code); } #endif } void mdb_iconv_close(MdbHandle *mdb) { #ifdef HAVE_ICONV if (mdb->iconv_out != (iconv_t)-1) iconv_close(mdb->iconv_out); if (mdb->iconv_in != (iconv_t)-1) iconv_close(mdb->iconv_in); #endif } mdbtools-0.7.1/src/libmdb/index.c000066400000000000000000000640221222645741400166500ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000-2004 Brian Bruns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "mdbtools.h" #ifdef DMALLOC #include "dmalloc.h" #endif MdbIndexPage *mdb_index_read_bottom_pg(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain); MdbIndexPage *mdb_chain_add_page(MdbHandle *mdb, MdbIndexChain *chain, guint32 pg); char idx_to_text[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0-7 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8-15 0x09-0x0f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 16-23 0x10-0x17 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 24-31 0x19-0x1f */ ' ', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 32-39 0x20-0x27 */ 0x00, 0x00, 0x00, 0x00, 0x00, ' ', ' ', 0x00, /* 40-47 0x29-0x2f */ 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', /* 48-55 0x30-0x37 */ '^', '_', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 56-63 0x39-0x3f */ 0x00, '`', 'a', 'b', 'd', 'f', 'g', 'h', /* 64-71 0x40-0x47 */ 'i', 'j', 'k', 'l', 'm', 'o', 'p', 'r', /* 72-79 0x49-0x4f H */ 's', 't', 'u', 'v', 'w', 'x', 'z', '{', /* 80-87 0x50-0x57 P */ '|', '}', '~', '5', '6', '7', '8', '9', /* 88-95 0x59-0x5f */ 0x00, '`', 'a', 'b', 'd', 'f', 'g', 'h', /* 96-103 0x60-0x67 */ 'i', 'j', 'k', 'l', 'm', 'o', 'p', 'r', /* 014-111 0x69-0x6f h */ 's', 't', 'u', 'v', 'w', 'x', 'z', '{', /* 112-119 0x70-0x77 p */ '|', '}', '~', 0x00, 0x00, 0x00, 0x00, 0x00, /* 120-127 0x78-0x7f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 128-135 0x80-0x87 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ 0x00, 0x00, 0x00, 0x00, 0x00, '`', 0x00, 0x00, /* 0xc0-0xc7 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ 0x00, '`', 0x00, '`', '`', '`', 0x00, 0x00, /* 0xe0-0xe7 */ 'f', 'f', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ 0x00, 0x00, 0x00, 'r', 0x00, 0x00, 'r', 0x00, /* 0xf0-0xf7 */ 0x81, 0x00, 0x00, 0x00, 'x', 0x00, 0x00, 0x00, /* 0xf8-0xff */ }; GPtrArray * mdb_read_indices(MdbTableDef *table) { MdbCatalogEntry *entry = table->entry; MdbHandle *mdb = entry->mdb; MdbFormatConstants *fmt = mdb->fmt; MdbIndex *pidx; unsigned int i, j, k; int key_num, col_num, cleaned_col_num; int cur_pos, name_sz, idx2_sz, type_offset; int index_start_pg = mdb->cur_pg; gchar *tmpbuf; table->indices = g_ptr_array_new(); if (IS_JET3(mdb)) { cur_pos = table->index_start + 39 * table->num_real_idxs; idx2_sz = 20; type_offset = 19; } else { cur_pos = table->index_start + 52 * table->num_real_idxs; idx2_sz = 28; type_offset = 23; } //fprintf(stderr, "num_idxs:%d num_real_idxs:%d\n", table->num_idxs, table->num_real_idxs); /* num_real_idxs should be the number of indexes of type 2. * It's not always the case. Happens on Northwind Orders table. */ table->num_real_idxs = 0; tmpbuf = (gchar *) g_malloc(idx2_sz); for (i=0;inum_idxs;i++) { read_pg_if_n(mdb, tmpbuf, &cur_pos, idx2_sz); pidx = (MdbIndex *) g_malloc0(sizeof(MdbIndex)); pidx->table = table; pidx->index_num = mdb_get_int16(tmpbuf, 4); pidx->index_type = tmpbuf[type_offset]; g_ptr_array_add(table->indices, pidx); /* { gint32 dumy0 = mdb_get_int32(tmpbuf, 0); gint8 dumy1 = tmpbuf[8]; gint32 dumy2 = mdb_get_int32(tmpbuf, 9); gint32 dumy3 = mdb_get_int32(tmpbuf, 13); gint16 dumy4 = mdb_get_int16(tmpbuf, 17); fprintf(stderr, "idx #%d: num2:%d type:%d\n", i, pidx->index_num, pidx->index_type); fprintf(stderr, "idx #%d: %d %d %d %d %d\n", i, dumy0, dumy1, dumy2, dumy3, dumy4); }*/ if (pidx->index_type!=2) table->num_real_idxs++; } //fprintf(stderr, "num_idxs:%d num_real_idxs:%d\n", table->num_idxs, table->num_real_idxs); g_free(tmpbuf); for (i=0;inum_idxs;i++) { pidx = g_ptr_array_index (table->indices, i); if (IS_JET3(mdb)) { name_sz=read_pg_if_8(mdb, &cur_pos); } else { name_sz=read_pg_if_16(mdb, &cur_pos); } tmpbuf = g_malloc(name_sz); read_pg_if_n(mdb, tmpbuf, &cur_pos, name_sz); mdb_unicode2ascii(mdb, tmpbuf, name_sz, pidx->name, MDB_MAX_OBJ_NAME); g_free(tmpbuf); //fprintf(stderr, "index %d type %d name %s\n", pidx->index_num, pidx->index_type, pidx->name); } mdb_read_alt_pg(mdb, entry->table_pg); mdb_read_pg(mdb, index_start_pg); cur_pos = table->index_start; for (i=0;inum_real_idxs;i++) { if (!IS_JET3(mdb)) cur_pos += 4; /* look for index number i */ for (j=0; jnum_idxs; ++j) { pidx = g_ptr_array_index (table->indices, j); if (pidx->index_type!=2 && pidx->index_num==i) break; } if (j==table->num_idxs) { fprintf(stderr, "ERROR: can't find index #%d.\n", i); continue; } //fprintf(stderr, "index %d #%d (%s) index_type:%d\n", i, pidx->index_num, pidx->name, pidx->index_type); pidx->num_rows = mdb_get_int32(mdb->alt_pg_buf, fmt->tab_cols_start_offset + (pidx->index_num*fmt->tab_ridx_entry_size)); /* fprintf(stderr, "ridx block1 i:%d data1:0x%08x data2:0x%08x\n", i, mdb_get_int32(mdb->pg_buf, fmt->tab_cols_start_offset + pidx->index_num * fmt->tab_ridx_entry_size), mdb_get_int32(mdb->pg_buf, fmt->tab_cols_start_offset + pidx->index_num * fmt->tab_ridx_entry_size +4)); fprintf(stderr, "pidx->num_rows:%d\n", pidx->num_rows);*/ key_num=0; for (j=0;jnum_cols; k++) { MdbColumn *col = g_ptr_array_index(table->columns,k); if (col->col_num == col_num) { cleaned_col_num = k; break; } } if (cleaned_col_num==-1) { fprintf(stderr, "CRITICAL: can't find column with internal id %d in index %s\n", col_num, pidx->name); cur_pos++; continue; } /* set column number to a 1 based column number and store */ pidx->key_col_num[key_num] = cleaned_col_num + 1; pidx->key_col_order[key_num] = (read_pg_if_8(mdb, &cur_pos)) ? MDB_ASC : MDB_DESC; //fprintf(stderr, "component %d using column #%d (internally %d)\n", j, cleaned_col_num, col_num); key_num++; } pidx->num_keys = key_num; cur_pos += 4; //fprintf(stderr, "pidx->unknown_pre_first_pg:0x%08x\n", read_pg_if_32(mdb, &cur_pos)); pidx->first_pg = read_pg_if_32(mdb, &cur_pos); pidx->flags = read_pg_if_8(mdb, &cur_pos); //fprintf(stderr, "pidx->first_pg:%d pidx->flags:0x%02x\n", pidx->first_pg, pidx->flags); if (!IS_JET3(mdb)) cur_pos += 9; } return NULL; } void mdb_index_hash_text(char *text, char *hash) { unsigned int k; for (k=0;k= 0; i--) { dest[j++] = src[i]; } } void mdb_index_cache_sarg(MdbColumn *col, MdbSarg *sarg, MdbSarg *idx_sarg) { //guint32 cache_int; unsigned char *c; switch (col->col_type) { case MDB_TEXT: mdb_index_hash_text(sarg->value.s, idx_sarg->value.s); break; case MDB_LONGINT: idx_sarg->value.i = GUINT32_SWAP_LE_BE(sarg->value.i); //cache_int = sarg->value.i * -1; c = (unsigned char *) &(idx_sarg->value.i); c[0] |= 0x80; //printf("int %08x %02x %02x %02x %02x\n", sarg->value.i, c[0], c[1], c[2], c[3]); break; case MDB_INT: break; default: break; } } #if 0 int mdb_index_test_sarg(MdbHandle *mdb, MdbColumn *col, MdbSarg *sarg, int offset, int len) { char tmpbuf[256]; int lastchar; switch (col->col_type) { case MDB_BYTE: return mdb_test_int(sarg, mdb_pg_get_byte(mdb, offset)); break; case MDB_INT: return mdb_test_int(sarg, mdb_pg_get_int16(mdb, offset)); break; case MDB_LONGINT: return mdb_test_int(sarg, mdb_pg_get_int32(mdb, offset)); break; case MDB_TEXT: strncpy(tmpbuf, &mdb->pg_buf[offset],255); lastchar = len > 255 ? 255 : len; tmpbuf[lastchar]='\0'; return mdb_test_string(sarg, tmpbuf); default: fprintf(stderr, "Calling mdb_test_sarg on unknown type. Add code to mdb_test_sarg() for type %d\n",col->col_type); break; } return 1; } #endif int mdb_index_test_sargs(MdbHandle *mdb, MdbIndex *idx, char *buf, int len) { unsigned int i, j; MdbColumn *col; MdbTableDef *table = idx->table; MdbSarg *idx_sarg; MdbSarg *sarg; MdbField field; MdbSargNode node; //int c_offset = 0, int c_len; //fprintf(stderr,"mdb_index_test_sargs called on "); //for (i=0;ipg_buf[offset+i]); //fprintf(stderr,"\n"); for (i=0;inum_keys;i++) { //c_offset++; /* the per column null indicator/flags */ col=g_ptr_array_index(table->columns,idx->key_col_num[i]-1); /* * This will go away eventually */ if (col->col_type==MDB_TEXT) { //c_len = strlen(&mdb->pg_buf[offset + c_offset]); c_len = strlen(buf); } else { c_len = col->col_size; //fprintf(stderr,"Only text types currently supported. How did we get here?\n"); } /* * If we have no cached index values for this column, * create them. */ if (col->num_sargs && !col->idx_sarg_cache) { col->idx_sarg_cache = g_ptr_array_new(); for (j=0;jnum_sargs;j++) { sarg = g_ptr_array_index (col->sargs, j); idx_sarg = g_memdup(sarg,sizeof(MdbSarg)); //printf("calling mdb_index_cache_sarg\n"); mdb_index_cache_sarg(col, sarg, idx_sarg); g_ptr_array_add(col->idx_sarg_cache, idx_sarg); } } for (j=0;jnum_sargs;j++) { sarg = g_ptr_array_index (col->idx_sarg_cache, j); /* XXX - kludge */ node.op = sarg->op; node.value = sarg->value; //field.value = &mdb->pg_buf[offset + c_offset]; field.value = buf; field.siz = c_len; field.is_null = FALSE; if (!mdb_test_sarg(mdb, col, &node, &field)) { /* sarg didn't match, no sense going on */ return 0; } } } return 1; } /* * pack the pages bitmap */ int mdb_index_pack_bitmap(MdbHandle *mdb, MdbIndexPage *ipg) { int mask_bit = 0; int mask_pos = 0x16; int mask_byte = 0; int elem = 0; int len, start, i; start = ipg->idx_starts[elem++]; while (start) { //fprintf(stdout, "elem %d is %d\n", elem, ipg->idx_starts[elem]); len = ipg->idx_starts[elem] - start; //fprintf(stdout, "len is %d\n", len); for (i=0; i < len; i++) { mask_bit++; if (mask_bit==8) { mask_bit=0; mdb->pg_buf[mask_pos++] = mask_byte; mask_byte = 0; } /* upon reaching the len, set the bit */ } mask_byte = (1 << mask_bit) | mask_byte; //fprintf(stdout, "mask byte is %02x at %d\n", mask_byte, mask_pos); start = ipg->idx_starts[elem++]; } /* flush the last byte if any */ mdb->pg_buf[mask_pos++] = mask_byte; /* remember to zero the rest of the bitmap */ for (i = mask_pos; i < 0xf8; i++) { mdb->pg_buf[mask_pos++] = 0; } return 0; } /* * unpack the pages bitmap */ int mdb_index_unpack_bitmap(MdbHandle *mdb, MdbIndexPage *ipg) { int mask_bit = 0; int mask_pos = 0x16; int mask_byte; int start = 0xf8; int elem = 0; int len = 0; ipg->idx_starts[elem++]=start; //fprintf(stdout, "Unpacking index page %lu\n", ipg->pg); do { len = 0; do { mask_bit++; if (mask_bit==8) { mask_bit=0; mask_pos++; } mask_byte = mdb->pg_buf[mask_pos]; len++; } while (mask_pos <= 0xf8 && !((1 << mask_bit) & mask_byte)); //fprintf(stdout, "%d %d %d %d\n", mask_pos, mask_bit, mask_byte, len); start += len; if (mask_pos < 0xf8) ipg->idx_starts[elem++]=start; } while (mask_pos < 0xf8); /* if we zero the next element, so we don't pick up the last pages starts*/ ipg->idx_starts[elem]=0; return elem; } /* * find the next entry on a page (either index or leaf). Uses state information * stored in the MdbIndexPage across calls. */ int mdb_index_find_next_on_page(MdbHandle *mdb, MdbIndexPage *ipg) { if (!ipg->pg) return 0; /* if this page has not been unpacked to it */ if (!ipg->idx_starts[0]){ //fprintf(stdout, "Unpacking page %d\n", ipg->pg); mdb_index_unpack_bitmap(mdb, ipg); } if (ipg->idx_starts[ipg->start_pos + 1]==0) return 0; ipg->len = ipg->idx_starts[ipg->start_pos+1] - ipg->idx_starts[ipg->start_pos]; ipg->start_pos++; //fprintf(stdout, "Start pos %d\n", ipg->start_pos); return ipg->len; } void mdb_index_page_reset(MdbIndexPage *ipg) { ipg->offset = 0xf8; /* start byte of the index entries */ ipg->start_pos=0; ipg->len = 0; ipg->idx_starts[0]=0; } void mdb_index_page_init(MdbIndexPage *ipg) { memset(ipg, 0, sizeof(MdbIndexPage)); mdb_index_page_reset(ipg); } /* * find the next leaf page if any given a chain. Assumes any exhausted leaf * pages at the end of the chain have been peeled off before the call. */ MdbIndexPage * mdb_find_next_leaf(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain) { MdbIndexPage *ipg, *newipg; guint32 pg; guint passed = 0; ipg = mdb_index_read_bottom_pg(mdb, idx, chain); /* * If we are at the first page deep and it's not an index page then * we are simply done. (there is no page to find */ if (mdb->pg_buf[0]==MDB_PAGE_LEAF) { /* Indexes can have leaves at the end that don't appear * in the upper tree, stash the last index found so * we can follow it at the end. */ chain->last_leaf_found = ipg->pg; return ipg; } /* * apply sargs here, currently we don't */ do { ipg->len = 0; //printf("finding next on pg %lu\n", ipg->pg); if (!mdb_index_find_next_on_page(mdb, ipg)) { //printf("find_next_on_page returned 0\n"); return 0; } pg = mdb_get_int32_msb(mdb->pg_buf, ipg->offset + ipg->len - 3) >> 8; //printf("Looking at pg %lu at %lu %d\n", pg, ipg->offset, ipg->len); ipg->offset += ipg->len; /* * add to the chain and call this function * recursively. */ newipg = mdb_chain_add_page(mdb, chain, pg); newipg = mdb_find_next_leaf(mdb, idx, chain); //printf("returning pg %lu\n",newipg->pg); return newipg; } while (!passed); /* no more pages */ return NULL; } MdbIndexPage * mdb_chain_add_page(MdbHandle *mdb, MdbIndexChain *chain, guint32 pg) { MdbIndexPage *ipg; chain->cur_depth++; if (chain->cur_depth > MDB_MAX_INDEX_DEPTH) { fprintf(stderr,"Error! maximum index depth of %d exceeded. This is probably due to a programming bug, If you are confident that your indexes really are this deep, adjust MDB_MAX_INDEX_DEPTH in mdbtools.h and recompile.\n", MDB_MAX_INDEX_DEPTH); exit(1); } ipg = &(chain->pages[chain->cur_depth - 1]); mdb_index_page_init(ipg); ipg->pg = pg; return ipg; } /* * returns the bottom page of the IndexChain, if IndexChain is empty it * initializes it by reading idx->first_pg (the root page) */ MdbIndexPage * mdb_index_read_bottom_pg(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain) { MdbIndexPage *ipg; /* * if it's new use the root index page (idx->first_pg) */ if (!chain->cur_depth) { ipg = &(chain->pages[0]); mdb_index_page_init(ipg); chain->cur_depth = 1; ipg->pg = idx->first_pg; if (!(ipg = mdb_find_next_leaf(mdb, idx, chain))) return 0; } else { ipg = &(chain->pages[chain->cur_depth - 1]); ipg->len = 0; } mdb_read_pg(mdb, ipg->pg); return ipg; } /* * unwind the stack and search for new leaf node */ MdbIndexPage * mdb_index_unwind(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain) { MdbIndexPage *ipg; //printf("page %lu finished\n",ipg->pg); if (chain->cur_depth==1) { //printf("cur_depth == 1 we're out\n"); return NULL; } /* * unwind the stack until we find something or reach * the top. */ ipg = NULL; while (chain->cur_depth>1 && ipg==NULL) { //printf("chain depth %d\n", chain->cur_depth); chain->cur_depth--; ipg = mdb_find_next_leaf(mdb, idx, chain); if (ipg) mdb_index_find_next_on_page(mdb, ipg); } if (chain->cur_depth==1) { //printf("last leaf %lu\n", chain->last_leaf_found); return NULL; } return ipg; } /* * the main index function. * caller provides an index chain which is the current traversal of index * pages from the root page to the leaf. Initially passed as blank, * mdb_index_find_next will store it's state information here. Each invocation * then picks up where the last one left off, allowing us to scroll through * the index one by one. * * Sargs are applied here but also need to be applied on the whole row b/c * text columns may return false positives due to hashing and non-index * columns with sarg values can't be tested here. */ int mdb_index_find_next(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain, guint32 *pg, guint16 *row) { MdbIndexPage *ipg; int passed = 0; int idx_sz; int idx_start = 0; MdbColumn *col; guint32 pg_row; ipg = mdb_index_read_bottom_pg(mdb, idx, chain); /* * loop while the sargs don't match */ do { ipg->len = 0; /* * if no more rows on this leaf, try to find a new leaf */ if (!mdb_index_find_next_on_page(mdb, ipg)) { if (!chain->clean_up_mode) { if (!(ipg = mdb_index_unwind(mdb, idx, chain))) chain->clean_up_mode = 1; } if (chain->clean_up_mode) { //fprintf(stdout,"in cleanup mode\n"); if (!chain->last_leaf_found) return 0; mdb_read_pg(mdb, chain->last_leaf_found); chain->last_leaf_found = mdb_get_int32( mdb->pg_buf, 0x0c); //printf("next leaf %lu\n", chain->last_leaf_found); mdb_read_pg(mdb, chain->last_leaf_found); /* reuse the chain for cleanup mode */ chain->cur_depth = 1; ipg = &chain->pages[0]; mdb_index_page_init(ipg); ipg->pg = chain->last_leaf_found; //printf("next on page %d\n", if (!mdb_index_find_next_on_page(mdb, ipg)) return 0; } } pg_row = mdb_get_int32_msb(mdb->pg_buf, ipg->offset + ipg->len - 4); *row = pg_row & 0xff; *pg = pg_row >> 8; //printf("row = %d pg = %lu ipg->pg = %lu offset = %lu len = %d\n", *row, *pg, ipg->pg, ipg->offset, ipg->len); col=g_ptr_array_index(idx->table->columns,idx->key_col_num[0]-1); idx_sz = mdb_col_fixed_size(col); /* handle compressed indexes, single key indexes only? */ if (idx->num_keys==1 && idx_sz>0 && ipg->len - 4 < idx_sz) { //printf("short index found\n"); //mdb_buffer_dump(ipg->cache_value, 0, idx_sz); memcpy(&ipg->cache_value[idx_sz - (ipg->len - 4)], &mdb->pg_buf[ipg->offset], ipg->len); //mdb_buffer_dump(ipg->cache_value, 0, idx_sz); } else { idx_start = ipg->offset + (ipg->len - 4 - idx_sz); memcpy(ipg->cache_value, &mdb->pg_buf[idx_start], idx_sz); } //idx_start = ipg->offset + (ipg->len - 4 - idx_sz); passed = mdb_index_test_sargs(mdb, idx, (char *)(ipg->cache_value), idx_sz); ipg->offset += ipg->len; } while (!passed); //fprintf(stdout,"len = %d pos %d\n", ipg->len, ipg->mask_pos); //mdb_buffer_dump(mdb->pg_buf, ipg->offset, ipg->len); return ipg->len; } /* * XXX - FIX ME * This function is grossly inefficient. It scans the entire index building * an IndexChain to a specific row. We should be checking the index pages * for matches against the indexed fields to find the proper leaf page, but * getting it working first and then make it fast! */ int mdb_index_find_row(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain, guint32 pg, guint16 row) { MdbIndexPage *ipg; int passed = 0; guint32 pg_row = (pg << 8) | (row & 0xff); guint32 datapg_row; ipg = mdb_index_read_bottom_pg(mdb, idx, chain); do { ipg->len = 0; /* * if no more rows on this leaf, try to find a new leaf */ if (!mdb_index_find_next_on_page(mdb, ipg)) { /* back to top? We're done */ if (chain->cur_depth==1) return 0; /* * unwind the stack until we find something or reach * the top. */ while (chain->cur_depth>1) { chain->cur_depth--; if (!(ipg = mdb_find_next_leaf(mdb, idx, chain))) return 0; mdb_index_find_next_on_page(mdb, ipg); } if (chain->cur_depth==1) return 0; } /* test row and pg */ datapg_row = mdb_get_int32_msb(mdb->pg_buf, ipg->offset + ipg->len - 4); if (pg_row == datapg_row) { passed = 1; } ipg->offset += ipg->len; } while (!passed); /* index chain from root to leaf should now be in "chain" */ return 1; } void mdb_index_walk(MdbTableDef *table, MdbIndex *idx) { /* MdbHandle *mdb = table->entry->mdb; int cur_pos = 0; unsigned char marker; MdbColumn *col; unsigned int i; if (idx->num_keys!=1) return; mdb_read_pg(mdb, idx->first_pg); cur_pos = 0xf8; for (i=0;inum_keys;i++) { marker = mdb->pg_buf[cur_pos++]; col=g_ptr_array_index(table->columns,idx->key_col_num[i]-1); //printf("column %d coltype %d col_size %d (%d)\n",i,col->col_type, mdb_col_fixed_size(col), col->col_size); } */ } void mdb_index_dump(MdbTableDef *table, MdbIndex *idx) { unsigned int i; MdbColumn *col; fprintf(stdout,"index number %d\n", idx->index_num); fprintf(stdout,"index name %s\n", idx->name); fprintf(stdout,"index first page %d\n", idx->first_pg); fprintf(stdout,"index rows %d\n", idx->num_rows); if (idx->index_type==1) fprintf(stdout,"index is a primary key\n"); for (i=0;inum_keys;i++) { col=g_ptr_array_index(table->columns,idx->key_col_num[i]-1); fprintf(stdout,"Column %s(%d) Sorted %s Unique: %s\n", col->name, idx->key_col_num[i], idx->key_col_order[i]==MDB_ASC ? "ascending" : "descending", idx->flags & MDB_IDX_UNIQUE ? "Yes" : "No" ); } mdb_index_walk(table, idx); } /* * compute_cost tries to assign a cost to a given index using the sargs * available in this query. * * Indexes with no matching sargs are assigned 0 * Unique indexes are preferred over non-uniques * Operator preference is equal, like, isnull, others */ int mdb_index_compute_cost(MdbTableDef *table, MdbIndex *idx) { unsigned int i; MdbColumn *col; MdbSarg *sarg = NULL; int not_all_equal = 0; if (!idx->num_keys) return 0; if (idx->num_keys > 1) { for (i=0;inum_keys;i++) { col=g_ptr_array_index(table->columns,idx->key_col_num[i]-1); if (col->sargs) sarg = g_ptr_array_index (col->sargs, 0); if (!sarg || sarg->op != MDB_EQUAL) not_all_equal++; } } col=g_ptr_array_index(table->columns,idx->key_col_num[0]-1); /* * if this is the first key column and there are no sargs, * then this index is useless. */ if (!col->num_sargs) return 0; sarg = g_ptr_array_index (col->sargs, 0); /* * a like with a wild card first is useless as a sarg */ if (sarg->op == MDB_LIKE && sarg->value.s[0]=='%') return 0; /* * this needs a lot of tweaking. */ if (idx->flags & MDB_IDX_UNIQUE) { if (idx->num_keys == 1) { //printf("op is %d\n", sarg->op); switch (sarg->op) { case MDB_EQUAL: return 1; break; case MDB_LIKE: return 4; break; case MDB_ISNULL: return 12; break; default: return 8; break; } } else { switch (sarg->op) { case MDB_EQUAL: if (not_all_equal) return 2; else return 1; break; case MDB_LIKE: return 6; break; case MDB_ISNULL: return 12; break; default: return 9; break; } } } else { if (idx->num_keys == 1) { switch (sarg->op) { case MDB_EQUAL: return 2; break; case MDB_LIKE: return 5; break; case MDB_ISNULL: return 12; break; default: return 10; break; } } else { switch (sarg->op) { case MDB_EQUAL: if (not_all_equal) return 3; else return 2; break; case MDB_LIKE: return 7; break; case MDB_ISNULL: return 12; break; default: return 11; break; } } } return 0; } /* * choose_index runs mdb_index_compute_cost for each available index and picks * the best. * * Returns strategy to use (table scan, or index scan) */ MdbStrategy mdb_choose_index(MdbTableDef *table, int *choice) { unsigned int i; MdbIndex *idx; int cost = 0; int least = 99; *choice = -1; for (i=0;inum_idxs;i++) { idx = g_ptr_array_index (table->indices, i); cost = mdb_index_compute_cost(table, idx); //printf("cost for %s is %d\n", idx->name, cost); if (cost && cost < least) { least = cost; *choice = i; } } /* and the winner is: *choice */ if (least==99) return MDB_TABLE_SCAN; return MDB_INDEX_SCAN; } void mdb_index_scan_init(MdbHandle *mdb, MdbTableDef *table) { int i; if (mdb_get_option(MDB_USE_INDEX) && mdb_choose_index(table, &i) == MDB_INDEX_SCAN) { table->strategy = MDB_INDEX_SCAN; table->scan_idx = g_ptr_array_index (table->indices, i); table->chain = g_malloc0(sizeof(MdbIndexChain)); table->mdbidx = mdb_clone_handle(mdb); mdb_read_pg(table->mdbidx, table->scan_idx->first_pg); //printf("best index is %s\n",table->scan_idx->name); } //printf("TABLE SCAN? %d\n", table->strategy); } void mdb_index_scan_free(MdbTableDef *table) { if (table->chain) { g_free(table->chain); table->chain = NULL; } if (table->mdbidx) { mdb_close(table->mdbidx); table->mdbidx = NULL; } } void mdb_free_indices(GPtrArray *indices) { unsigned int i; if (!indices) return; for (i=0; ilen; i++) g_free (g_ptr_array_index(indices, i)); g_ptr_array_free(indices, TRUE); } mdbtools-0.7.1/src/libmdb/like.c000066400000000000000000000042751222645741400164710ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "mdbtools.h" #ifdef DMALLOC #include "dmalloc.h" #endif /** * mdb_like_cmp * @s: String to search within. * @r: Search pattern. * * Tests the string @s to see if it matches the search pattern @r. In the * search pattern, a percent sign indicates matching on any number of * characters, and an underscore indicates matching any single character. * * Returns: 1 if the string matches, 0 if the string does not match. */ int mdb_like_cmp(char *s, char *r) { unsigned int i; int ret; mdb_debug(MDB_DEBUG_LIKE, "comparing %s and %s", s, r); switch (r[0]) { case '\0': if (s[0]=='\0') { return 1; } else { return 0; } case '_': /* skip one character */ return mdb_like_cmp(&s[1],&r[1]); case '%': /* skip any number of characters */ /* the strlen(s)+1 is important so the next call can */ /* if there are trailing characters */ for(i=0;i= pgnum) ? start_pg-pgnum+1 : 0; for (; ifmt->pg_size - 4) * 8 pages. * * map_ind gives us the starting usage_map entry * offset gives us a page offset into the bitmap */ usage_bitlen = (mdb->fmt->pg_size - 4) * 8; max_map_pgs = (map_sz - 1) / 4; map_ind = (start_pg + 1) / usage_bitlen; offset = (start_pg + 1) % usage_bitlen; for (; map_indfmt->pg_size) { fprintf(stderr, "Oops! didn't get a full page at %d\n", map_pg); exit(1); } usage_bitmap = mdb->alt_pg_buf + 4; for (i=offset; ientry; MdbHandle *mdb = entry->mdb; guint32 pgnum; guint32 cur_pg = 0; int free_space; do { pgnum = mdb_map_find_next(mdb, table->free_usage_map, table->freemap_sz, cur_pg); //printf("looking at page %d\n", pgnum); if (!pgnum) { /* allocate new page */ pgnum = mdb_alloc_page(table); return pgnum; } else if (pgnum==-1) { fprintf(stderr, "Error: mdb_map_find_next_freepage error while reading maps.\n"); exit(1); } cur_pg = pgnum; mdb_read_pg(mdb, pgnum); free_space = mdb_pg_get_freespace(mdb); } while (free_space < row_size); //printf("page %d has %d bytes left\n", pgnum, free_space); return pgnum; } mdbtools-0.7.1/src/libmdb/mem.c000066400000000000000000000021261222645741400163140ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database files * Copyright (C) 2000 Brian Bruns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "mdbtools.h" MDB_DEPRECATED(void, mdb_init()) { fprintf(stderr, "mdb_init() is DEPRECATED and does nothing. Stop calling it.\n"); } MDB_DEPRECATED(void, mdb_exit()) { fprintf(stderr, "mdb_exit() is DEPRECATED and does nothing. Stop calling it.\n"); } mdbtools-0.7.1/src/libmdb/money.c000066400000000000000000000115161222645741400166700ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 1998-1999 Brian Bruns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "mdbtools.h" #ifdef DMALLOC #include "dmalloc.h" #endif #define MAX_NUMERIC_PRECISION 28 /* ** these routines are copied from the freetds project which does something ** very similiar */ static int multiply_byte(unsigned char *product, int num, unsigned char *multiplier); static int do_carry(unsigned char *product); static char *array_to_string(unsigned char *array, int unsigned scale, int neg); /** * mdb_money_to_string * @mdb: Handle to open MDB database file * @start: Offset of the field within the current page * * Returns: the allocated string that has received the value. */ char *mdb_money_to_string(MdbHandle *mdb, int start) { int num_bytes=8, scale=4; int i; int neg=0; unsigned char multiplier[MAX_NUMERIC_PRECISION], temp[MAX_NUMERIC_PRECISION]; unsigned char product[MAX_NUMERIC_PRECISION]; unsigned char bytes[num_bytes]; memset(multiplier,0,MAX_NUMERIC_PRECISION); memset(product,0,MAX_NUMERIC_PRECISION); multiplier[0]=1; memcpy(bytes, mdb->pg_buf + start, num_bytes); /* Perform two's complement for negative numbers */ if (bytes[num_bytes-1] & 0x80) { neg = 1; for (i=0;ipg_buf + start + 1, num_bytes); /* Perform two's complement for negative numbers */ if (mdb->pg_buf[start] & 0x80) neg = 1; for (i=0;i9) { product[j+1]+=product[j]/10; product[j]=product[j]%10; } } if (product[j]>9) { product[j]=product[j]%10; } return 0; } static char *array_to_string(unsigned char *array, unsigned int scale, int neg) { char *s; unsigned int top, i, j=0; for (top=MAX_NUMERIC_PRECISION;(top>0) && (top-1>scale) && !array[top-1];top--); /* allocate enough space for all digits + minus sign + decimal point + trailing NULL byte */ s = (char *) g_malloc(MAX_NUMERIC_PRECISION+3); if (neg) s[j++] = '-'; if (top == 0) { s[j++] = '0'; } else { for (i=top; i>0; i--) { if (i == scale) s[j++]='.'; s[j++]=array[i-1]+'0'; } } s[j]='\0'; return s; } mdbtools-0.7.1/src/libmdb/options.c000066400000000000000000000044501222645741400172330ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2004 Brian Bruns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include "mdbtools.h" #ifdef DMALLOC #include "dmalloc.h" #endif #define DEBUG 1 static unsigned long opts; static int optset; static void load_options(); void mdb_debug(int klass, char *fmt, ...) { #ifdef DEBUG va_list ap; if (!optset) load_options(); if (klass & opts) { va_start(ap, fmt); vfprintf (stderr,fmt, ap); va_end(ap); fprintf(stderr,"\n"); } #endif } static void load_options() { char *opt; char *s; if (!optset && (s=getenv("MDBOPTS"))) { opt = strtok(s, ":"); while (opt) { if (!strcmp(opt, "use_index")) opts |= MDB_USE_INDEX; if (!strcmp(opt, "no_memo")) opts |= MDB_NO_MEMO; if (!strcmp(opt, "debug_like")) opts |= MDB_DEBUG_LIKE; if (!strcmp(opt, "debug_write")) opts |= MDB_DEBUG_WRITE; if (!strcmp(opt, "debug_usage")) opts |= MDB_DEBUG_USAGE; if (!strcmp(opt, "debug_ole")) opts |= MDB_DEBUG_OLE; if (!strcmp(opt, "debug_row")) opts |= MDB_DEBUG_ROW; if (!strcmp(opt, "debug_props")) opts |= MDB_DEBUG_PROPS; if (!strcmp(opt, "debug_all")) { opts |= MDB_DEBUG_LIKE; opts |= MDB_DEBUG_WRITE; opts |= MDB_DEBUG_USAGE; opts |= MDB_DEBUG_OLE; opts |= MDB_DEBUG_ROW; opts |= MDB_DEBUG_PROPS; } opt = strtok(NULL,":"); } } optset = 1; } int mdb_get_option(unsigned long optnum) { if (!optset) load_options(); return ((opts & optnum) > 0); } mdbtools-0.7.1/src/libmdb/props.c000066400000000000000000000131331222645741400167010ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000-2011 Brian Bruns and others * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "mdbtools.h" static GPtrArray * mdb_read_props_list(MdbHandle *mdb, gchar *kkd, int len) { guint32 record_len; int pos = 0; gchar *name; GPtrArray *names = NULL; int i=0; names = g_ptr_array_new(); #if MDB_DEBUG mdb_buffer_dump(kkd, 0, len); #endif pos = 0; while (pos < len) { record_len = mdb_get_int16(kkd, pos); pos += 2; if (mdb_get_option(MDB_DEBUG_PROPS)) { fprintf(stderr, "%02d ",i++); mdb_buffer_dump(kkd, pos - 2, record_len + 2); } name = g_malloc(3*record_len + 1); /* worst case scenario is 3 bytes out per byte in */ mdb_unicode2ascii(mdb, &kkd[pos], record_len, name, 3*record_len); pos += record_len; g_ptr_array_add(names, name); #if MDB_DEBUG printf("new len = %d\n", names->len); #endif } return names; } static gboolean free_hash_entry(gpointer key, gpointer value, gpointer user_data) { g_free(key); g_free(value); return TRUE; } void mdb_free_props(MdbProperties *props) { if (!props) return; if (props->name) g_free(props->name); if (props->hash) { g_hash_table_foreach(props->hash, (GHFunc)free_hash_entry, 0); g_hash_table_destroy(props->hash); } g_free(props); } static void free_names(GPtrArray *names) { g_ptr_array_foreach(names, (GFunc)g_free, NULL); g_ptr_array_free(names, TRUE); } MdbProperties * mdb_alloc_props() { MdbProperties *props; props = g_malloc0(sizeof(MdbProperties)); return props; } static MdbProperties * mdb_read_props(MdbHandle *mdb, GPtrArray *names, gchar *kkd, int len) { guint32 record_len, name_len; int pos = 0; int elem, dtype, dsize; gchar *name, *value; MdbProperties *props; int i=0; #if MDB_DEBUG mdb_buffer_dump(kkd, 0, len); #endif pos = 0; record_len = mdb_get_int16(kkd, pos); pos += 4; name_len = mdb_get_int16(kkd, pos); pos += 2; props = mdb_alloc_props(); if (name_len) { props->name = g_malloc(3*name_len + 1); mdb_unicode2ascii(mdb, kkd+pos, name_len, props->name, 3*name_len); mdb_debug(MDB_DEBUG_PROPS,"prop block named: %s", props->name); } pos += name_len; props->hash = g_hash_table_new(g_str_hash, g_str_equal); while (pos < len) { record_len = mdb_get_int16(kkd, pos); dtype = kkd[pos + 3]; elem = mdb_get_int16(kkd, pos + 4); dsize = mdb_get_int16(kkd, pos + 6); value = g_malloc(dsize + 1); strncpy(value, &kkd[pos + 8], dsize); value[dsize] = '\0'; name = g_ptr_array_index(names,elem); if (mdb_get_option(MDB_DEBUG_PROPS)) { fprintf(stderr, "%02d ",i++); mdb_debug(MDB_DEBUG_PROPS,"elem %d (%s) dsize %d dtype %d", elem, name, dsize, dtype); mdb_buffer_dump(value, 0, dsize); } if (dtype == MDB_MEMO) dtype = MDB_TEXT; if (dtype == MDB_BOOL) { g_hash_table_insert(props->hash, g_strdup(name), g_strdup(kkd[pos + 8] ? "yes" : "no")); } else { g_hash_table_insert(props->hash, g_strdup(name), mdb_col_to_string(mdb, kkd, pos + 8, dtype, dsize)); } g_free(value); pos += record_len; } return props; } static void print_keyvalue(gpointer key, gpointer value, gpointer outfile) { fprintf((FILE*)outfile,"\t%s: %s\n", (gchar *)key, (gchar *)value); } void mdb_dump_props(MdbProperties *props, FILE *outfile, int show_name) { if (show_name) fprintf(outfile,"name: %s\n", props->name ? props->name : "(none)"); g_hash_table_foreach(props->hash, print_keyvalue, outfile); if (show_name) fputc('\n', outfile); } /* * That function takes a raw KKD/MR2 binary buffer, * typically read from LvProp in table MSysbjects * and returns a GArray of MdbProps* */ GArray* mdb_kkd_to_props(MdbHandle *mdb, void *buffer, size_t len) { guint32 record_len; guint16 record_type; size_t pos; GPtrArray *names = NULL; MdbProperties *props; GArray *result; #if MDB_DEBUG mdb_buffer_dump(buffer, 0, len); #endif mdb_debug(MDB_DEBUG_PROPS,"starting prop parsing of type %s", buffer); if (strcmp("KKD", buffer) && strcmp("MR2", buffer)) { fprintf(stderr, "Unrecognized format.\n"); mdb_buffer_dump(buffer, 0, len); return NULL; } result = g_array_new(0, 0, sizeof(MdbProperties*)); pos = 4; while (pos < len) { record_len = mdb_get_int32(buffer, pos); record_type = mdb_get_int16(buffer, pos + 4); mdb_debug(MDB_DEBUG_PROPS,"prop chunk type:0x%04x len:%d", record_type, record_len); //mdb_buffer_dump(buffer, pos+4, record_len); switch (record_type) { case 0x80: if (names) free_names(names); names = mdb_read_props_list(mdb, buffer+pos+6, record_len - 6); break; case 0x00: case 0x01: if (!names) { fprintf(stderr,"sequence error!\n"); break; } props = mdb_read_props(mdb, names, buffer+pos+6, record_len - 6); g_array_append_val(result, props); //mdb_dump_props(props, stderr, 1); break; default: fprintf(stderr,"Unknown record type %d\n", record_type); break; } pos += record_len; } if (names) free_names(names); return result; } mdbtools-0.7.1/src/libmdb/sargs.c000066400000000000000000000174301222645741400166610ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* * code for handling searchable arguments (sargs) used primary by the sql * engine to support where clause handling. The sargs are configured in * a tree with AND/OR operators connecting the child nodes. NOT operations * have only one child on the left side. Logical operators (=,<,>,etc..) * have no children. * * datatype support is a bit weak at this point. To add more types create * a mdb_test_[type]() function and invoke it from mdb_test_sarg() */ #include #include "mdbtools.h" #ifdef DMALLOC #include "dmalloc.h" #endif void mdb_sql_walk_tree(MdbSargNode *node, MdbSargTreeFunc func, gpointer data) { if (func(node, data)) return; if (node->left) mdb_sql_walk_tree(node->left, func, data); if (node->right) mdb_sql_walk_tree(node->right, func, data); } int mdb_test_string(MdbSargNode *node, char *s) { int rc; if (node->op == MDB_LIKE) { return mdb_like_cmp(s,node->value.s); } rc = strncmp(node->value.s, s, 255); switch (node->op) { case MDB_EQUAL: if (rc==0) return 1; break; case MDB_GT: if (rc<0) return 1; break; case MDB_LT: if (rc>0) return 1; break; case MDB_GTEQ: if (rc<=0) return 1; break; case MDB_LTEQ: if (rc>=0) return 1; break; default: fprintf(stderr, "Calling mdb_test_sarg on unknown operator. Add code to mdb_test_string() for operator %d\n",node->op); break; } return 0; } int mdb_test_int(MdbSargNode *node, gint32 i) { switch (node->op) { case MDB_EQUAL: //fprintf(stderr, "comparing %ld and %ld\n", i, node->value.i); if (node->value.i == i) return 1; break; case MDB_GT: if (node->value.i < i) return 1; break; case MDB_LT: if (node->value.i > i) return 1; break; case MDB_GTEQ: if (node->value.i <= i) return 1; break; case MDB_LTEQ: if (node->value.i >= i) return 1; break; default: fprintf(stderr, "Calling mdb_test_sarg on unknown operator. Add code to mdb_test_int() for operator %d\n",node->op); break; } return 0; } int mdb_test_date(MdbSargNode *node, double td) { struct tm found; /* TODO: you should figure out a way to pull mdb_date_to_string in here * char date_tmp[MDB_BIND_SIZE]; */ time_t found_t; time_t asked_t; double diff; mdb_date_to_tm(td, &found); asked_t = node->value.i; found_t = mktime(&found); diff = difftime(asked_t, found_t); switch (node->op) { case MDB_EQUAL: if (diff==0) return 1; break; case MDB_GT: if (diff<0) return 1; break; case MDB_LT: if (diff>0) return 1; break; case MDB_GTEQ: if (diff<=0) return 1; break; case MDB_LTEQ: if (diff>=0) return 1; break; default: fprintf(stderr, "Calling mdb_test_sarg on unknown operator. Add code to mdb_test_date() for operator %d\n", node->op); break; } return 0; } int mdb_find_indexable_sargs(MdbSargNode *node, gpointer data) { MdbSarg sarg; if (node->op == MDB_OR || node->op == MDB_NOT) return 1; /* * right now all we do is look for sargs that are anded together from * the root. Later we may put together OR ops into a range, and then * range scan the leaf pages. That is col1 = 2 or col1 = 4 becomes * col1 >= 2 and col1 <= 4 for the purpose of index scans, and then * extra rows are thrown out when the row is tested against the main * sarg tree. range scans are generally only a bit better than table * scanning anyway. * * also, later we should support the NOT operator, but it's generally * a pretty worthless test for indexes, ie NOT col1 = 3, we are * probably better off table scanning. */ if (mdb_is_relational_op(node->op) && node->col) { //printf("op = %d value = %s\n", node->op, node->value.s); sarg.op = node->op; sarg.value = node->value; mdb_add_sarg(node->col, &sarg); } return 0; } int mdb_test_sarg(MdbHandle *mdb, MdbColumn *col, MdbSargNode *node, MdbField *field) { char tmpbuf[256]; if (node->op == MDB_ISNULL) { if (field->is_null) return 0; else return 1; } else if (node->op == MDB_NOTNULL) { if (field->is_null) return 1; else return 0; } switch (col->col_type) { case MDB_BOOL: return mdb_test_int(node, !field->is_null); break; case MDB_BYTE: return mdb_test_int(node, (gint32)((char *)field->value)[0]); break; case MDB_INT: return mdb_test_int(node, (gint32)mdb_get_int16(field->value, 0)); break; case MDB_LONGINT: return mdb_test_int(node, (gint32)mdb_get_int32(field->value, 0)); break; case MDB_TEXT: mdb_unicode2ascii(mdb, field->value, field->siz, tmpbuf, 256); return mdb_test_string(node, tmpbuf); case MDB_DATETIME: return mdb_test_date(node, mdb_get_double(field->value, 0)); default: fprintf(stderr, "Calling mdb_test_sarg on unknown type. Add code to mdb_test_sarg() for type %d\n",col->col_type); break; } return 1; } int mdb_find_field(int col_num, MdbField *fields, int num_fields) { int i; for (i=0;iop)) { col = node->col; /* for const = const expressions */ if (!col) { return (node->value.i); } elem = mdb_find_field(col->col_num, fields, num_fields); if (!mdb_test_sarg(mdb, col, node, &fields[elem])) return 0; } else { /* logical op */ switch (node->op) { case MDB_NOT: rc = mdb_test_sarg_node(mdb, node->left, fields, num_fields); return !rc; break; case MDB_AND: if (!mdb_test_sarg_node(mdb, node->left, fields, num_fields)) return 0; return mdb_test_sarg_node(mdb, node->right, fields, num_fields); break; case MDB_OR: if (mdb_test_sarg_node(mdb, node->left, fields, num_fields)) return 1; return mdb_test_sarg_node(mdb, node->right, fields, num_fields); break; } } return 1; } int mdb_test_sargs(MdbTableDef *table, MdbField *fields, int num_fields) { MdbSargNode *node; MdbCatalogEntry *entry = table->entry; MdbHandle *mdb = entry->mdb; node = table->sarg_tree; /* there may not be a sarg tree */ if (!node) return 1; return mdb_test_sarg_node(mdb, node, fields, num_fields); } #if 0 int mdb_test_sargs(MdbHandle *mdb, MdbColumn *col, int offset, int len) { MdbSarg *sarg; int i; for (i=0;inum_sargs;i++) { sarg = g_ptr_array_index (col->sargs, i); if (!mdb_test_sarg(mdb, col, sarg, offset, len)) { /* sarg didn't match, no sense going on */ return 0; } } return 1; } #endif int mdb_add_sarg(MdbColumn *col, MdbSarg *in_sarg) { MdbSarg *sarg; if (!col->sargs) { col->sargs = g_ptr_array_new(); } sarg = g_memdup(in_sarg,sizeof(MdbSarg)); g_ptr_array_add(col->sargs, sarg); col->num_sargs++; return 1; } int mdb_add_sarg_by_name(MdbTableDef *table, char *colname, MdbSarg *in_sarg) { MdbColumn *col; unsigned int i; for (i=0;inum_cols;i++) { col = g_ptr_array_index (table->columns, i); if (!strcasecmp(col->name,colname)) { return mdb_add_sarg(col, in_sarg); } } /* else didn't find the column return 0! */ return 0; } mdbtools-0.7.1/src/libmdb/stats.c000066400000000000000000000040641222645741400166770ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database files * Copyright (C) 2000 Brian Bruns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "mdbtools.h" #ifdef DMALLOC #include "dmalloc.h" #endif /** * mdb_stats_on: * @mdb: Handle to the (open) MDB file to collect stats on. * * Begins collection of statistics on an MDBHandle. * * Statistics in LibMDB will track the number of reads from the MDB file. The * collection of statistics is started and stopped with the mdb_stats_on and * mdb_stats_off functions. Collected statistics are accessed by reading the * MdbStatistics structure or calling mdb_dump_stats. * */ void mdb_stats_on(MdbHandle *mdb) { if (!mdb->stats) mdb->stats = g_malloc0(sizeof(MdbStatistics)); mdb->stats->collect = TRUE; } /** * mdb_stats_off: * @mdb: pointer to handle of MDB file with active stats collection. * * Turns off statistics collection. * * If mdb_stats_off is not called, statistics will be turned off when handle * is freed using mdb_close. **/ void mdb_stats_off(MdbHandle *mdb) { if (!mdb->stats) return; mdb->stats->collect = FALSE; } /** * mdb_dump_stats: * @mdb: pointer to handle of MDB file with active stats collection. * * Dumps current statistics to stdout. **/ void mdb_dump_stats(MdbHandle *mdb) { if (!mdb->stats) return; fprintf(stdout, "Physical Page Reads: %lu\n", mdb->stats->pg_reads); } mdbtools-0.7.1/src/libmdb/table.c000066400000000000000000000261621222645741400166330ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "mdbtools.h" #ifdef DMALLOC #include "dmalloc.h" #endif static gint mdb_col_comparer(MdbColumn **a, MdbColumn **b) { if ((*a)->col_num > (*b)->col_num) return 1; else if ((*a)->col_num < (*b)->col_num) return -1; else return 0; } unsigned char mdb_col_needs_size(int col_type) { if (col_type == MDB_TEXT) { return TRUE; } else { return FALSE; } } MdbTableDef *mdb_alloc_tabledef(MdbCatalogEntry *entry) { MdbTableDef *table; table = (MdbTableDef *) g_malloc0(sizeof(MdbTableDef)); table->entry=entry; strcpy(table->name, entry->object_name); return table; } void mdb_free_tabledef(MdbTableDef *table) { if (!table) return; if (table->is_temp_table) { unsigned int i; /* Temp table pages are being stored in memory */ for (i=0; itemp_table_pages->len; i++) g_free(g_ptr_array_index(table->temp_table_pages,i)); g_ptr_array_free(table->temp_table_pages, TRUE); /* Temp tables use dummy entries */ g_free(table->entry); } mdb_free_columns(table->columns); mdb_free_indices(table->indices); g_free(table->usage_map); g_free(table->free_usage_map); g_free(table); } MdbTableDef *mdb_read_table(MdbCatalogEntry *entry) { MdbTableDef *table; MdbHandle *mdb = entry->mdb; MdbFormatConstants *fmt = mdb->fmt; int row_start, pg_row; void *buf, *pg_buf = mdb->pg_buf; guint i; mdb_read_pg(mdb, entry->table_pg); if (mdb_get_byte(pg_buf, 0) != 0x02) /* not a valid table def page */ return NULL; table = mdb_alloc_tabledef(entry); mdb_get_int16(pg_buf, 8); /* len */ table->num_rows = mdb_get_int32(pg_buf, fmt->tab_num_rows_offset); table->num_var_cols = mdb_get_int16(pg_buf, fmt->tab_num_cols_offset-2); table->num_cols = mdb_get_int16(pg_buf, fmt->tab_num_cols_offset); table->num_idxs = mdb_get_int32(pg_buf, fmt->tab_num_idxs_offset); table->num_real_idxs = mdb_get_int32(pg_buf, fmt->tab_num_ridxs_offset); /* grab a copy of the usage map */ pg_row = mdb_get_int32(pg_buf, fmt->tab_usage_map_offset); mdb_find_pg_row(mdb, pg_row, &buf, &row_start, &(table->map_sz)); table->usage_map = g_memdup(buf + row_start, table->map_sz); if (mdb_get_option(MDB_DEBUG_USAGE)) mdb_buffer_dump(buf, row_start, table->map_sz); mdb_debug(MDB_DEBUG_USAGE,"usage map found on page %ld row %d start %d len %d", pg_row >> 8, pg_row & 0xff, row_start, table->map_sz); /* grab a copy of the free space page map */ pg_row = mdb_get_int32(pg_buf, fmt->tab_free_map_offset); mdb_find_pg_row(mdb, pg_row, &buf, &row_start, &(table->freemap_sz)); table->free_usage_map = g_memdup(buf + row_start, table->freemap_sz); mdb_debug(MDB_DEBUG_USAGE,"free map found on page %ld row %d start %d len %d\n", pg_row >> 8, pg_row & 0xff, row_start, table->freemap_sz); table->first_data_pg = mdb_get_int16(pg_buf, fmt->tab_first_dpg_offset); if (entry->props) for (i=0; iprops->len; ++i) { MdbProperties *props = g_array_index(entry->props, MdbProperties*, i); if (!props->name) table->props = props; } return table; } MdbTableDef *mdb_read_table_by_name(MdbHandle *mdb, gchar *table_name, int obj_type) { unsigned int i; MdbCatalogEntry *entry; mdb_read_catalog(mdb, obj_type); for (i=0; inum_catalog; i++) { entry = g_ptr_array_index(mdb->catalog, i); if (!strcasecmp(entry->object_name, table_name)) return mdb_read_table(entry); } return NULL; } guint32 read_pg_if_32(MdbHandle *mdb, int *cur_pos) { char c[4]; read_pg_if_n(mdb, c, cur_pos, 4); return mdb_get_int32(c, 0); } guint16 read_pg_if_16(MdbHandle *mdb, int *cur_pos) { char c[2]; read_pg_if_n(mdb, c, cur_pos, 2); return mdb_get_int16(c, 0); } guint8 read_pg_if_8(MdbHandle *mdb, int *cur_pos) { guint8 c; read_pg_if_n(mdb, &c, cur_pos, 1); return c; } /* * Read data into a buffer, advancing pages and setting the * page cursor as needed. In the case that buf in NULL, pages * are still advanced and the page cursor is still updated. */ void * read_pg_if_n(MdbHandle *mdb, void *buf, int *cur_pos, size_t len) { /* Advance to page which contains the first byte */ while (*cur_pos >= mdb->fmt->pg_size) { mdb_read_pg(mdb, mdb_get_int32(mdb->pg_buf,4)); *cur_pos -= (mdb->fmt->pg_size - 8); } /* Copy pages into buffer */ while (*cur_pos + len >= mdb->fmt->pg_size) { int piece_len = mdb->fmt->pg_size - *cur_pos; if (buf) { memcpy(buf, mdb->pg_buf + *cur_pos, piece_len); buf += piece_len; } len -= piece_len; mdb_read_pg(mdb, mdb_get_int32(mdb->pg_buf,4)); *cur_pos = 8; } /* Copy into buffer from final page */ if (len && buf) { memcpy(buf, mdb->pg_buf + *cur_pos, len); } *cur_pos += len; return buf; } void mdb_append_column(GPtrArray *columns, MdbColumn *in_col) { g_ptr_array_add(columns, g_memdup(in_col,sizeof(MdbColumn))); } void mdb_free_columns(GPtrArray *columns) { unsigned int i, j; MdbColumn *col; if (!columns) return; for (i=0; ilen; i++) { col = (MdbColumn *) g_ptr_array_index(columns, i); if (col->sargs) { for (j=0; jsargs->len; j++) { g_free( g_ptr_array_index(col->sargs, j)); } g_ptr_array_free(col->sargs, TRUE); } g_free(col); } g_ptr_array_free(columns, TRUE); } GPtrArray *mdb_read_columns(MdbTableDef *table) { MdbHandle *mdb = table->entry->mdb; MdbFormatConstants *fmt = mdb->fmt; MdbColumn *pcol; unsigned char *col; unsigned int i, j; int cur_pos; size_t name_sz; GArray *allprops; table->columns = g_ptr_array_new(); col = (unsigned char *) g_malloc(fmt->tab_col_entry_size); cur_pos = fmt->tab_cols_start_offset + (table->num_real_idxs * fmt->tab_ridx_entry_size); /* new code based on patch submitted by Tim Nelson 2000.09.27 */ /* ** column attributes */ for (i=0;inum_cols;i++) { #ifdef MDB_DEBUG /* printf("column %d\n", i); mdb_buffer_dump(mdb->pg_buf, cur_pos, fmt->tab_col_entry_size); */ #endif read_pg_if_n(mdb, col, &cur_pos, fmt->tab_col_entry_size); pcol = (MdbColumn *) g_malloc0(sizeof(MdbColumn)); pcol->table = table; pcol->col_type = col[0]; // col_num_offset == 1 or 5 pcol->col_num = col[fmt->col_num_offset]; //fprintf(stdout,"----- column %d -----\n",pcol->col_num); // col_var == 3 or 7 pcol->var_col_num = mdb_get_int16(col, fmt->tab_col_offset_var); //fprintf(stdout,"var column pos %d\n",pcol->var_col_num); // col_var == 5 or 9 pcol->row_col_num = mdb_get_int16(col, fmt->tab_row_col_num_offset); //fprintf(stdout,"row column num %d\n",pcol->row_col_num); /* FIXME: can this be right in Jet3 and Jet4? */ if (pcol->col_type == MDB_NUMERIC) { pcol->col_prec = col[11]; pcol->col_scale = col[12]; } // col_flags_offset == 13 or 15 pcol->is_fixed = col[fmt->col_flags_offset] & 0x01 ? 1 : 0; pcol->is_long_auto = col[fmt->col_flags_offset] & 0x04 ? 1 : 0; pcol->is_uuid_auto = col[fmt->col_flags_offset] & 0x40 ? 1 : 0; // tab_col_offset_fixed == 14 or 21 pcol->fixed_offset = mdb_get_int16(col, fmt->tab_col_offset_fixed); //fprintf(stdout,"fixed column offset %d\n",pcol->fixed_offset); //fprintf(stdout,"col type %s\n",pcol->is_fixed ? "fixed" : "variable"); if (pcol->col_type != MDB_BOOL) { // col_size_offset == 16 or 23 pcol->col_size = mdb_get_int16(col, fmt->col_size_offset); } else { pcol->col_size=0; } g_ptr_array_add(table->columns, pcol); } g_free (col); /* ** column names - ordered the same as the column attributes table */ for (i=0;inum_cols;i++) { char *tmp_buf; pcol = g_ptr_array_index(table->columns, i); if (IS_JET3(mdb)) name_sz = read_pg_if_8(mdb, &cur_pos); else name_sz = read_pg_if_16(mdb, &cur_pos); tmp_buf = (char *) g_malloc(name_sz); read_pg_if_n(mdb, tmp_buf, &cur_pos, name_sz); mdb_unicode2ascii(mdb, tmp_buf, name_sz, pcol->name, MDB_MAX_OBJ_NAME); g_free(tmp_buf); } /* Sort the columns by col_num */ g_ptr_array_sort(table->columns, (GCompareFunc)mdb_col_comparer); allprops = table->entry->props; if (allprops) for (i=0;inum_cols;i++) { pcol = g_ptr_array_index(table->columns, i); for (j=0; jlen; ++j) { MdbProperties *props = g_array_index(allprops, MdbProperties*, j); if (props->name && pcol->name && !strcmp(props->name, pcol->name)) { pcol->props = props; break; } } } table->index_start = cur_pos; return table->columns; } void mdb_table_dump(MdbCatalogEntry *entry) { MdbTableDef *table; MdbColumn *col; int coln; MdbIndex *idx; unsigned int i, bitn; guint32 pgnum; table = mdb_read_table(entry); fprintf(stdout,"definition page = %lu\n",entry->table_pg); fprintf(stdout,"number of datarows = %d\n",table->num_rows); fprintf(stdout,"number of columns = %d\n",table->num_cols); fprintf(stdout,"number of indices = %d\n",table->num_real_idxs); if (table->props) mdb_dump_props(table->props, stdout, 0); mdb_read_columns(table); mdb_read_indices(table); for (i=0;inum_cols;i++) { col = g_ptr_array_index(table->columns,i); fprintf(stdout,"column %d Name: %-20s Type: %s(%d)\n", i, col->name, mdb_get_colbacktype_string(col), col->col_size); if (col->props) mdb_dump_props(col->props, stdout, 0); } for (i=0;inum_idxs;i++) { idx = g_ptr_array_index (table->indices, i); mdb_index_dump(table, idx); } if (table->usage_map) { printf("pages reserved by this object\n"); printf("usage map pg %" G_GUINT32_FORMAT "\n", table->map_base_pg); printf("free map pg %" G_GUINT32_FORMAT "\n", table->freemap_base_pg); pgnum = mdb_get_int32(table->usage_map,1); /* the first 5 bytes of the usage map mean something */ coln = 0; for (i=5;imap_sz;i++) { for (bitn=0;bitn<8;bitn++) { if (table->usage_map[i] & 1 << bitn) { coln++; printf("%6" G_GUINT32_FORMAT, pgnum); if (coln==10) { printf("\n"); coln = 0; } else { printf(" "); } } pgnum++; } } printf("\n"); } } int mdb_is_user_table(MdbCatalogEntry *entry) { return ((entry->object_type == MDB_TABLE) && !(entry->flags & 0x80000002)) ? 1 : 0; } int mdb_is_system_table(MdbCatalogEntry *entry) { return ((entry->object_type == MDB_TABLE) && (entry->flags & 0x80000002)) ? 1 : 0; } const char * mdb_table_get_prop(const MdbTableDef *table, const gchar *key) { if (!table->props) return NULL; return g_hash_table_lookup(table->props->hash, key); } const char * mdb_col_get_prop(const MdbColumn *col, const gchar *key) { if (!col->props) return NULL; return g_hash_table_lookup(col->props->hash, key); } mdbtools-0.7.1/src/libmdb/worktable.c000066400000000000000000000053701222645741400175340ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database files * Copyright (C) 2004 Brian Bruns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "mdbtools.h" #ifdef DMALLOC #include "dmalloc.h" #endif /* * Temp table routines. These are currently used to generate mock results for * commands like "list tables" and "describe table" */ void mdb_fill_temp_col(MdbColumn *tcol, char *col_name, int col_size, int col_type, int is_fixed) { memset(tcol,0,sizeof(MdbColumn)); strcpy(tcol->name, col_name); tcol->col_type = col_type; if ((col_type == MDB_TEXT) || (col_type == MDB_MEMO)) { tcol->col_size = col_size; } else { tcol->col_size = mdb_col_fixed_size(tcol); } tcol->is_fixed = is_fixed; } void mdb_fill_temp_field(MdbField *field, void *value, int siz, int is_fixed, int is_null, int start, int colnum) { field->value = value; field->siz = siz; field->is_fixed = is_fixed; field->is_null = is_null; field->start = start; field->colnum = colnum; } MdbTableDef * mdb_create_temp_table(MdbHandle *mdb, char *name) { MdbCatalogEntry *entry; MdbTableDef *table; /* dummy up a catalog entry */ entry = (MdbCatalogEntry *) g_malloc0(sizeof(MdbCatalogEntry)); entry->mdb = mdb; entry->object_type = MDB_TABLE; entry->table_pg = 0; strcpy(entry->object_name, name); table = mdb_alloc_tabledef(entry); table->columns = g_ptr_array_new(); table->is_temp_table = 1; table->temp_table_pages = g_ptr_array_new(); return table; } void mdb_temp_table_add_col(MdbTableDef *table, MdbColumn *col) { col->table = table, col->col_num = table->num_cols; if (!col->is_fixed) col->var_col_num = table->num_var_cols++; g_ptr_array_add(table->columns, g_memdup(col, sizeof(MdbColumn))); table->num_cols++; } /* * Should be called after setting up all temp table columns */ void mdb_temp_columns_end(MdbTableDef *table) { MdbColumn *col; unsigned int i; unsigned int start = 0; for (i=0; inum_cols; i++) { col = g_ptr_array_index(table->columns, i); if (col->is_fixed) { col->fixed_offset = start; start += col->col_size; } } } mdbtools-0.7.1/src/libmdb/write.c000066400000000000000000000605661222645741400167040ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include "mdbtools.h" #ifdef DMALLOC #include "dmalloc.h" #endif //static int mdb_copy_index_pg(MdbTableDef *table, MdbIndex *idx, MdbIndexPage *ipg); static int mdb_add_row_to_leaf_pg(MdbTableDef *table, MdbIndex *idx, MdbIndexPage *ipg, MdbField *idx_fields, guint32 pgnum, guint16 rownum); void mdb_put_int16(void *buf, guint32 offset, guint32 value) { value = GINT32_TO_LE(value); memcpy(buf + offset, &value, 2); } void _mdb_put_int16(void *buf, guint32 offset, guint32 value) #ifdef HAVE_ATTRIBUTE_ALIAS __attribute__((alias("mdb_put_int16"))); #else { mdb_put_int16(buf, offset, value); } #endif void mdb_put_int32(void *buf, guint32 offset, guint32 value) { value = GINT32_TO_LE(value); memcpy(buf + offset, &value, 4); } void _mdb_put_int32(void *buf, guint32 offset, guint32 value) #ifdef HAVE_ATTRIBUTE_ALIAS __attribute__((alias("mdb_put_int32"))); #else { mdb_put_int32(buf, offset, value); } #endif void mdb_put_int32_msb(void *buf, guint32 offset, guint32 value) { value = GINT32_TO_BE(value); memcpy(buf + offset, &value, 4); } void _mdb_put_int32_mdb(void *buf, guint32 offset, guint32 value) #ifdef HAVE_ATTRIBUTE_ALIAS __attribute__((alias("mdb_put_int32_msb"))); #else { mdb_put_int32_msb(buf, offset, value); } #endif ssize_t mdb_write_pg(MdbHandle *mdb, unsigned long pg) { ssize_t len; struct stat status; off_t offset = pg * mdb->fmt->pg_size; fstat(mdb->f->fd, &status); /* is page beyond current size + 1 ? */ if (status.st_size < offset + mdb->fmt->pg_size) { fprintf(stderr,"offset %jd is beyond EOF\n",(intmax_t)offset); return 0; } lseek(mdb->f->fd, offset, SEEK_SET); len = write(mdb->f->fd,mdb->pg_buf,mdb->fmt->pg_size); if (len==-1) { perror("write"); return 0; } else if (lenfmt->pg_size) { /* fprintf(stderr,"EOF reached %d bytes returned.\n",len, mdb->pg_size); */ return 0; } mdb->cur_pos = 0; return len; } static int mdb_is_col_indexed(MdbTableDef *table, int colnum) { unsigned int i, j; MdbIndex *idx; for (i=0;inum_idxs;i++) { idx = g_ptr_array_index (table->indices, i); for (j=0;jnum_keys;j++) { if (idx->key_col_num[j]==colnum) return 1; } } return 0; } static void mdb_crack_row4(MdbHandle *mdb, int row_start, int row_end, unsigned int bitmask_sz, unsigned int row_var_cols, unsigned int *var_col_offsets) { unsigned int i; for (i=0; ipg_buf, row_end - bitmask_sz - 3 - (i*2)); } } static void mdb_crack_row3(MdbHandle *mdb, int row_start, int row_end, unsigned int bitmask_sz, unsigned int row_var_cols, unsigned int *var_col_offsets) { unsigned int i; unsigned int num_jumps = 0, jumps_used = 0; unsigned int col_ptr, row_len; row_len = row_end - row_start + 1; num_jumps = (row_len - 1) / 256; col_ptr = row_end - bitmask_sz - num_jumps - 1; /* If last jump is a dummy value, ignore it */ if ((col_ptr-row_start-row_var_cols)/256 < num_jumps) num_jumps--; jumps_used = 0; for (i=0; ipg_buf[row_end-bitmask_sz-jumps_used-1])) { jumps_used++; } var_col_offsets[i] = mdb->pg_buf[col_ptr-i]+(jumps_used*256); } } /** * mdb_crack_row: * @table: Table that the row belongs to * @row_start: offset to start of row on current page * @row_end: offset to end of row on current page * @fields: pointer to MdbField array to be popluated by mdb_crack_row * * Cracks a row buffer apart into its component fields. * * A row buffer is that portion of a data page which contains the values for * that row. Its beginning and end can be found in the row offset table. * * The resulting MdbField array contains pointers into the row for each field * present. Be aware that by modifying field[]->value, you would be modifying * the row buffer itself, not a copy. * * This routine is mostly used internally by mdb_fetch_row() but may have some * applicability for advanced application programs. * * Return value: number of fields present. */ int mdb_crack_row(MdbTableDef *table, int row_start, int row_end, MdbField *fields) { MdbColumn *col; MdbCatalogEntry *entry = table->entry; MdbHandle *mdb = entry->mdb; void *pg_buf = mdb->pg_buf; unsigned int row_var_cols=0, row_cols; unsigned char *nullmask; unsigned int bitmask_sz; unsigned int *var_col_offsets = NULL; unsigned int fixed_cols_found, row_fixed_cols; unsigned int col_count_size; unsigned int i; if (mdb_get_option(MDB_DEBUG_ROW)) { mdb_buffer_dump(pg_buf, row_start, row_end - row_start + 1); } if (IS_JET3(mdb)) { row_cols = mdb_get_byte(pg_buf, row_start); col_count_size = 1; } else { row_cols = mdb_get_int16(pg_buf, row_start); col_count_size = 2; } bitmask_sz = (row_cols + 7) / 8; nullmask = pg_buf + row_end - bitmask_sz + 1; /* read table of variable column locations */ if (table->num_var_cols > 0) { row_var_cols = IS_JET3(mdb) ? mdb_get_byte(pg_buf, row_end - bitmask_sz) : mdb_get_int16(pg_buf, row_end - bitmask_sz - 1); var_col_offsets = (unsigned int *)g_malloc((row_var_cols+1)*sizeof(int)); if (IS_JET3(mdb)) { mdb_crack_row3(mdb, row_start, row_end, bitmask_sz, row_var_cols, var_col_offsets); } else { mdb_crack_row4(mdb, row_start, row_end, bitmask_sz, row_var_cols, var_col_offsets); } } fixed_cols_found = 0; row_fixed_cols = row_cols - row_var_cols; if (mdb_get_option(MDB_DEBUG_ROW)) { fprintf(stdout,"bitmask_sz %d\n", bitmask_sz); fprintf(stdout,"row_var_cols %d\n", row_var_cols); fprintf(stdout,"row_fixed_cols %d\n", row_fixed_cols); } for (i=0;inum_cols;i++) { unsigned int byte_num, bit_num; unsigned int col_start; col = g_ptr_array_index(table->columns,i); fields[i].colnum = i; fields[i].is_fixed = col->is_fixed; byte_num = col->col_num / 8; bit_num = col->col_num % 8; /* logic on nulls is reverse, 1 is not null, 0 is null */ fields[i].is_null = nullmask[byte_num] & (1 << bit_num) ? 0 : 1; if ((fields[i].is_fixed) && (fixed_cols_found < row_fixed_cols)) { col_start = col->fixed_offset + col_count_size; fields[i].start = row_start + col_start; fields[i].value = pg_buf + row_start + col_start; fields[i].siz = col->col_size; fixed_cols_found++; /* Use col->var_col_num because a deleted column is still * present in the variable column offsets table for the row */ } else if ((!fields[i].is_fixed) && (col->var_col_num < row_var_cols)) { col_start = var_col_offsets[col->var_col_num]; fields[i].start = row_start + col_start; fields[i].value = pg_buf + row_start + col_start; fields[i].siz = var_col_offsets[(col->var_col_num)+1] - col_start; } else { fields[i].start = 0; fields[i].value = NULL; fields[i].siz = 0; fields[i].is_null = 1; } } g_free(var_col_offsets); return row_cols; } static int mdb_pack_null_mask(unsigned char *buffer, int num_fields, MdbField *fields) { int pos = 0, bit = 0, byte = 0; int i; /* 'Not null' bitmap */ for (i=0; i> 8) & 0xff; /* Fixed length columns */ for (i=0;inum_var_cols == 0) { pos += mdb_pack_null_mask(&row_buffer[pos], num_fields, fields); return pos; } /* Variable length columns */ for (i=0;i> 8) & 0xff; pos += 2; /* Offsets of the variable-length columns */ for (i=num_fields; i>0; i--) { if (!fields[i-1].is_fixed) { row_buffer[pos++] = fields[i-1].offset & 0xff; row_buffer[pos++] = (fields[i-1].offset >> 8) & 0xff; } } /* Number of variable-length columns */ row_buffer[pos++] = var_cols & 0xff; row_buffer[pos++] = (var_cols >> 8) & 0xff; pos += mdb_pack_null_mask(&row_buffer[pos], num_fields, fields); return pos; } static int mdb_pack_row3(MdbTableDef *table, unsigned char *row_buffer, unsigned int num_fields, MdbField *fields) { unsigned int pos = 0; unsigned int var_cols = 0; unsigned int i, j; unsigned char *offset_high; row_buffer[pos++] = num_fields; /* Fixed length columns */ for (i=0;inum_var_cols == 0) { pos += mdb_pack_null_mask(&row_buffer[pos], num_fields, fields); return pos; } /* Variable length columns */ for (i=0;i> 8) & 0xff; j = 1; /* EOD */ row_buffer[pos] = pos & 0xff; pos++; /* Variable length column offsets */ for (i=num_fields; i>0; i--) { if (!fields[i-1].is_fixed) { row_buffer[pos++] = fields[i-1].offset & 0xff; offset_high[j++] = (fields[i-1].offset >> 8) & 0xff; } } /* Dummy jump table entry */ if (offset_high[0] < (pos+(num_fields+7)/8-1)/255) { row_buffer[pos++] = 0xff; } /* Jump table */ for (i=0; i offset_high[i+1]) { row_buffer[pos++] = var_cols-i; } } g_free(offset_high); row_buffer[pos++] = var_cols; pos += mdb_pack_null_mask(&row_buffer[pos], num_fields, fields); return pos; } int mdb_pack_row(MdbTableDef *table, unsigned char *row_buffer, int unsigned num_fields, MdbField *fields) { if (table->is_temp_table) { unsigned int i; for (i=0; icolumns, i); fields[i].is_null = (fields[i].value) ? 0 : 1; fields[i].colnum = i; fields[i].is_fixed = c->is_fixed; if ((c->col_type != MDB_TEXT) && (c->col_type != MDB_MEMO)) { fields[i].siz = c->col_size; } } } if (IS_JET3(table->entry->mdb)) { return mdb_pack_row3(table, row_buffer, num_fields, fields); } else { return mdb_pack_row4(table, row_buffer, num_fields, fields); } } int mdb_pg_get_freespace(MdbHandle *mdb) { int rows, free_start, free_end; int row_count_offset = mdb->fmt->row_count_offset; rows = mdb_get_int16(mdb->pg_buf, row_count_offset); free_start = row_count_offset + 2 + (rows * 2); free_end = mdb_get_int16(mdb->pg_buf, row_count_offset + (rows * 2)); mdb_debug(MDB_DEBUG_WRITE,"free space left on page = %d", free_end - free_start); return (free_end - free_start); } void * mdb_new_leaf_pg(MdbCatalogEntry *entry) { MdbHandle *mdb = entry->mdb; void *new_pg = g_malloc0(mdb->fmt->pg_size); mdb_put_int16(new_pg, 0, 0x0104); mdb_put_int32(new_pg, 4, entry->table_pg); return new_pg; } void * mdb_new_data_pg(MdbCatalogEntry *entry) { MdbFormatConstants *fmt = entry->mdb->fmt; void *new_pg = g_malloc0(fmt->pg_size); mdb_put_int16(new_pg, 0, 0x0101); mdb_put_int16(new_pg, 2, fmt->pg_size - fmt->row_count_offset - 2); mdb_put_int32(new_pg, 4, entry->table_pg); return new_pg; } /* could be static */ int mdb_update_indexes(MdbTableDef *table, int num_fields, MdbField *fields, guint32 pgnum, guint16 rownum) { unsigned int i; MdbIndex *idx; for (i=0;inum_idxs;i++) { idx = g_ptr_array_index (table->indices, i); mdb_debug(MDB_DEBUG_WRITE,"Updating %s (%d).", idx->name, idx->index_type); if (idx->index_type==1) { mdb_update_index(table, idx, num_fields, fields, pgnum, rownum); } } return 1; } int mdb_init_index_chain(MdbTableDef *table, MdbIndex *idx) { MdbCatalogEntry *entry = table->entry; MdbHandle *mdb = entry->mdb; table->scan_idx = idx; table->chain = g_malloc0(sizeof(MdbIndexChain)); table->mdbidx = mdb_clone_handle(mdb); mdb_read_pg(table->mdbidx, table->scan_idx->first_pg); return 1; } /* could be static */ int mdb_update_index(MdbTableDef *table, MdbIndex *idx, unsigned int num_fields, MdbField *fields, guint32 pgnum, guint16 rownum) { MdbCatalogEntry *entry = table->entry; MdbHandle *mdb = entry->mdb; /*int idx_xref[16];*/ unsigned int i, j; MdbIndexChain *chain; MdbField idx_fields[10]; for (i = 0; i < idx->num_keys; i++) { for (j = 0; j < num_fields; j++) { // key_col_num is 1 based, can't remember why though if (fields[j].colnum == idx->key_col_num[i]-1) { /* idx_xref[i] = j; */ idx_fields[i] = fields[j]; } } } /* for (i = 0; i < idx->num_keys; i++) { fprintf(stdout, "key col %d (%d) is mapped to field %d (%d %d)\n", i, idx->key_col_num[i], idx_xref[i], fields[idx_xref[i]].colnum, fields[idx_xref[i]].siz); } for (i = 0; i < num_fields; i++) { fprintf(stdout, "%d (%d %d)\n", i, fields[i].colnum, fields[i].siz); } */ chain = g_malloc0(sizeof(MdbIndexChain)); mdb_index_find_row(mdb, idx, chain, pgnum, rownum); //printf("chain depth = %d\n", chain->cur_depth); //printf("pg = %" G_GUINT32_FORMAT "\n", //chain->pages[chain->cur_depth-1].pg); //mdb_copy_index_pg(table, idx, &chain->pages[chain->cur_depth-1]); mdb_add_row_to_leaf_pg(table, idx, &chain->pages[chain->cur_depth-1], idx_fields, pgnum, rownum); return 1; } int mdb_insert_row(MdbTableDef *table, int num_fields, MdbField *fields) { int new_row_size; unsigned char row_buffer[4096]; MdbCatalogEntry *entry = table->entry; MdbHandle *mdb = entry->mdb; MdbFormatConstants *fmt = mdb->fmt; guint32 pgnum; guint16 rownum; if (!mdb->f->writable) { fprintf(stderr, "File is not open for writing\n"); return 0; } new_row_size = mdb_pack_row(table, row_buffer, num_fields, fields); if (mdb_get_option(MDB_DEBUG_WRITE)) { mdb_buffer_dump(row_buffer, 0, new_row_size); } pgnum = mdb_map_find_next_freepage(table, new_row_size); if (!pgnum) { fprintf(stderr, "Unable to allocate new page.\n"); return 0; } rownum = mdb_add_row_to_pg(table, row_buffer, new_row_size); if (mdb_get_option(MDB_DEBUG_WRITE)) { mdb_buffer_dump(mdb->pg_buf, 0, 40); mdb_buffer_dump(mdb->pg_buf, fmt->pg_size - 160, 160); } mdb_debug(MDB_DEBUG_WRITE, "writing page %d", pgnum); if (!mdb_write_pg(mdb, pgnum)) { fprintf(stderr, "write failed!\n"); return 0; } mdb_update_indexes(table, num_fields, fields, pgnum, rownum); return 1; } /* * Assumes caller has verfied space is available on page and adds the new * row to the current pg_buf. */ guint16 mdb_add_row_to_pg(MdbTableDef *table, unsigned char *row_buffer, int new_row_size) { void *new_pg; int num_rows, i, pos, row_start; size_t row_size; MdbCatalogEntry *entry = table->entry; MdbHandle *mdb = entry->mdb; MdbFormatConstants *fmt = mdb->fmt; if (table->is_temp_table) { GPtrArray *pages = table->temp_table_pages; if (pages->len == 0) { new_pg = mdb_new_data_pg(entry); g_ptr_array_add(pages, new_pg); } else { new_pg = g_ptr_array_index(pages, pages->len - 1); if (mdb_get_int16(new_pg, 2) < new_row_size + 2) { new_pg = mdb_new_data_pg(entry); g_ptr_array_add(pages, new_pg); } } num_rows = mdb_get_int16(new_pg, fmt->row_count_offset); pos = (num_rows == 0) ? fmt->pg_size : mdb_get_int16(new_pg, fmt->row_count_offset + (num_rows*2)); } else { /* is not a temp table */ new_pg = mdb_new_data_pg(entry); num_rows = mdb_get_int16(mdb->pg_buf, fmt->row_count_offset); pos = fmt->pg_size; /* copy existing rows */ for (i=0;ipg_buf + row_start, row_size); mdb_put_int16(new_pg, (fmt->row_count_offset + 2) + (i*2), pos); } } /* add our new row */ pos -= new_row_size; memcpy(new_pg + pos, row_buffer, new_row_size); /* add row to the row offset table */ mdb_put_int16(new_pg, (fmt->row_count_offset + 2) + (num_rows*2), pos); /* update number rows on this page */ num_rows++; mdb_put_int16(new_pg, fmt->row_count_offset, num_rows); /* update the freespace */ mdb_put_int16(new_pg,2,pos - fmt->row_count_offset - 2 - (num_rows*2)); /* copy new page over old */ if (!table->is_temp_table) { memcpy(mdb->pg_buf, new_pg, fmt->pg_size); g_free(new_pg); } return num_rows; } int mdb_update_row(MdbTableDef *table) { int row_start, row_end; unsigned int i; MdbColumn *col; MdbCatalogEntry *entry = table->entry; MdbHandle *mdb = entry->mdb; MdbField fields[256]; unsigned char row_buffer[4096]; size_t old_row_size, new_row_size; unsigned int num_fields; if (!mdb->f->writable) { fprintf(stderr, "File is not open for writing\n"); return 0; } mdb_find_row(mdb, table->cur_row-1, &row_start, &old_row_size); row_end = row_start + old_row_size - 1; row_start &= 0x0FFF; /* remove flags */ mdb_debug(MDB_DEBUG_WRITE,"page %lu row %d start %d end %d", (unsigned long) table->cur_phys_pg, table->cur_row-1, row_start, row_end); if (mdb_get_option(MDB_DEBUG_LIKE)) mdb_buffer_dump(mdb->pg_buf, row_start, old_row_size); for (i=0;inum_cols;i++) { col = g_ptr_array_index(table->columns,i); if (col->bind_ptr && mdb_is_col_indexed(table,i)) { fprintf(stderr, "Attempting to update column that is part of an index\n"); return 0; } } num_fields = mdb_crack_row(table, row_start, row_end, fields); if (mdb_get_option(MDB_DEBUG_WRITE)) { for (i=0;inum_cols;i++) { col = g_ptr_array_index(table->columns,i); if (col->bind_ptr) { fields[i].value = col->bind_ptr; fields[i].siz = *(col->len_ptr); } } new_row_size = mdb_pack_row(table, row_buffer, num_fields, fields); if (mdb_get_option(MDB_DEBUG_WRITE)) mdb_buffer_dump(row_buffer, 0, new_row_size); if (new_row_size > (old_row_size + mdb_pg_get_freespace(mdb))) { fprintf(stderr, "No space left on this page, update will not occur\n"); return 0; } /* do it! */ mdb_replace_row(table, table->cur_row-1, row_buffer, new_row_size); return 0; /* FIXME */ } /* WARNING the return code is opposite to convention used elsewhere: * returns 0 on success * returns 1 on failure * This might change on next ABI break. */ int mdb_replace_row(MdbTableDef *table, int row, void *new_row, int new_row_size) { MdbCatalogEntry *entry = table->entry; MdbHandle *mdb = entry->mdb; int pg_size = mdb->fmt->pg_size; int rco = mdb->fmt->row_count_offset; void *new_pg; guint16 num_rows; int row_start; size_t row_size; int i, pos; if (mdb_get_option(MDB_DEBUG_WRITE)) { mdb_buffer_dump(mdb->pg_buf, 0, 40); mdb_buffer_dump(mdb->pg_buf, pg_size - 160, 160); } mdb_debug(MDB_DEBUG_WRITE,"updating row %d on page %lu", row, (unsigned long) table->cur_phys_pg); new_pg = mdb_new_data_pg(entry); num_rows = mdb_get_int16(mdb->pg_buf, rco); mdb_put_int16(new_pg, rco, num_rows); pos = pg_size; /* rows before */ for (i=0;ipg_buf + row_start, row_size); mdb_put_int16(new_pg, rco + 2 + i*2, pos); } /* our row */ pos -= new_row_size; memcpy(new_pg + pos, new_row, new_row_size); mdb_put_int16(new_pg, rco + 2 + row*2, pos); /* rows after */ for (i=row+1;ipg_buf + row_start, row_size); mdb_put_int16(new_pg, rco + 2 + i*2, pos); } /* almost done, copy page over current */ memcpy(mdb->pg_buf, new_pg, pg_size); g_free(new_pg); mdb_put_int16(mdb->pg_buf, 2, mdb_pg_get_freespace(mdb)); if (mdb_get_option(MDB_DEBUG_WRITE)) { mdb_buffer_dump(mdb->pg_buf, 0, 40); mdb_buffer_dump(mdb->pg_buf, pg_size - 160, 160); } /* drum roll, please */ if (!mdb_write_pg(mdb, table->cur_phys_pg)) { fprintf(stderr, "write failed!\n"); return 1; } return 0; } static int mdb_add_row_to_leaf_pg(MdbTableDef *table, MdbIndex *idx, MdbIndexPage *ipg, MdbField *idx_fields, guint32 pgnum, guint16 rownum) /*, guint32 pgnum, guint16 rownum) static int mdb_copy_index_pg(MdbTableDef *table, MdbIndex *idx, MdbIndexPage *ipg) */ { MdbCatalogEntry *entry = table->entry; MdbHandle *mdb = entry->mdb; MdbColumn *col; guint32 pg_row; guint16 row = 0; void *new_pg; unsigned char key_hash[256]; int keycol; new_pg = mdb_new_leaf_pg(entry); /* reinitial ipg pointers to start of page */ mdb_index_page_reset(ipg); mdb_read_pg(mdb, ipg->pg); /* do we support this index type yet? */ if (idx->num_keys > 1) { fprintf(stderr,"multikey indexes not yet supported, aborting\n"); return 0; } keycol = idx->key_col_num[0]; col = g_ptr_array_index (table->columns, keycol - 1); if (!col->is_fixed) { fprintf(stderr,"variable length key columns not yet supported, aborting\n"); return 0; } while (mdb_index_find_next_on_page(mdb, ipg)) { /* check for compressed indexes. */ if (ipg->len < col->col_size + 1) { fprintf(stderr,"compressed indexes not yet supported, aborting\n"); return 0; } pg_row = mdb_get_int32_msb(mdb->pg_buf, ipg->offset + ipg->len - 4); /* guint32 pg = pg_row >> 8; */ row = pg_row & 0xff; /* unsigned char iflag = mdb->pg_buf[ipg->offset]; */ /* turn the key hash back into a value */ mdb_index_swap_n(&mdb->pg_buf[ipg->offset + 1], col->col_size, key_hash); key_hash[col->col_size - 1] &= 0x7f; if (mdb_get_option(MDB_DEBUG_WRITE)) { mdb_buffer_dump(mdb->pg_buf, ipg->offset, ipg->len); mdb_buffer_dump(mdb->pg_buf, ipg->offset + 1, col->col_size); mdb_buffer_dump(key_hash, 0, col->col_size); } memcpy(new_pg + ipg->offset, mdb->pg_buf + ipg->offset, ipg->len); ipg->offset += ipg->len; ipg->len = 0; row++; } if (!row) { fprintf(stderr,"missing indexes not yet supported, aborting\n"); return 0; } //mdb_put_int16(new_pg, mdb->fmt->row_count_offset, row); /* free space left */ mdb_put_int16(new_pg, 2, mdb->fmt->pg_size - ipg->offset); //printf("offset = %d\n", ipg->offset); mdb_index_swap_n(idx_fields[0].value, col->col_size, key_hash); key_hash[0] |= 0x080; if (mdb_get_option(MDB_DEBUG_WRITE)) { printf("key_hash\n"); mdb_buffer_dump(idx_fields[0].value, 0, col->col_size); mdb_buffer_dump(key_hash, 0, col->col_size); printf("--------\n"); } ((char *)new_pg)[ipg->offset] = 0x7f; memcpy(new_pg + ipg->offset + 1, key_hash, col->col_size); pg_row = (pgnum << 8) | ((rownum-1) & 0xff); mdb_put_int32_msb(new_pg, ipg->offset + 5, pg_row); ipg->idx_starts[row++] = ipg->offset + ipg->len; //ipg->idx_starts[row] = ipg->offset + ipg->len; if (mdb_get_option(MDB_DEBUG_WRITE)) { mdb_buffer_dump(mdb->pg_buf, 0, mdb->fmt->pg_size); } memcpy(mdb->pg_buf, new_pg, mdb->fmt->pg_size); mdb_index_pack_bitmap(mdb, ipg); if (mdb_get_option(MDB_DEBUG_WRITE)) { mdb_buffer_dump(mdb->pg_buf, 0, mdb->fmt->pg_size); } g_free(new_pg); return ipg->len; } mdbtools-0.7.1/src/odbc/000077500000000000000000000000001222645741400150475ustar00rootroot00000000000000mdbtools-0.7.1/src/odbc/Makefile.am000066400000000000000000000013151222645741400171030ustar00rootroot00000000000000noinst_PROGRAMS = unittest lib_LTLIBRARIES = libmdbodbc.la AM_CFLAGS = -I$(top_srcdir)/include $(GLIB_CFLAGS) $(ODBC_CFLAGS) libmdbodbc_la_SOURCES = odbc.c connectparams.c mdbodbc.h connectparams.h libmdbodbc_la_LIBADD = ../libmdb/libmdb.la ../sql/libmdbsql.la libmdbodbc_la_LDFLAGS = -avoid-version -export-symbols-regex '^(SQL|ODBCINST)' if ICONV lib_LTLIBRARIES += libmdbodbcW.la libmdbodbcW_la_SOURCES = $(libmdbodbc_la_SOURCES) libmdbodbcW_la_LIBADD = $(libmdbodbc_la_LIBADD) @LIBICONV@ libmdbodbcW_la_LDFLAGS = $(libmdbodbc_la_LDFLAGS) libmdbodbcW_la_CFLAGS = $(AM_CFLAGS) -D ENABLE_ODBC_W=1 endif LIBS = @LEXLIB@ $(GLIB_LIBS) $(ODBC_LIBS) unittest_LDADD = libmdbodbc.la ../libmdb/libmdb.la ../sql/libmdbsql.la mdbtools-0.7.1/src/odbc/connectparams.c000066400000000000000000000302221222645741400200470ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000-2004 Brian Bruns * * portions based on FreeTDS, Copyright (C) 1998-1999 Brian Bruns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include "connectparams.h" /* * * Last resort place to check for INI file. This is usually set at compile time * * by build scripts. * */ #ifndef SYS_ODBC_INI #define SYS_ODBC_INI "/etc/odbc.ini" #endif #if defined(FILENAME_MAX) && FILENAME_MAX < 512 #undef FILENAME_MAX #define FILENAME_MAX 512 #endif #define max_line 256 static char line[max_line]; static guint HashFunction (gconstpointer key); #if HAVE_SQLGETPRIVATEPROFILESTRING #include extern int SQLGetPrivateProfileString( LPCSTR lpszSection, LPCSTR lpszEntry, LPCSTR lpszDefault, LPSTR lpszRetBuffer, int cbRetBuffer, LPCSTR lpszFilename); #else static GString* GetIniFileName (); static int FileExists (const gchar* name); static int FindSection (FILE* stream, const char* section); static int GetNextItem (FILE* stream, char** name, char** value); #endif //HAVE_SQLGETPRIVATEPROFILESTRING static void visit (gpointer key, gpointer value, gpointer user_data); static gboolean cleanup (gpointer key, gpointer value, gpointer user_data); /* * Allocate create a ConnectParams object */ ConnectParams* NewConnectParams () { ConnectParams* params = (ConnectParams *) g_malloc(sizeof (ConnectParams)); if (!params) return params; params->dsnName = g_string_new (""); params->iniFileName = NULL; params->table = g_hash_table_new (HashFunction, g_str_equal); return params; } /* * Destroy a ConnectParams object */ void FreeConnectParams (ConnectParams* params) { if (params) { if (params->dsnName) g_string_free (params->dsnName, TRUE); if (params->iniFileName) g_string_free (params->iniFileName, TRUE); if (params->table) { g_hash_table_foreach_remove (params->table, cleanup, NULL); g_hash_table_destroy (params->table); } g_free(params); } } #if !HAVE_SQLGETPRIVATEPROFILESTRING static int LoadDSN ( const gchar* iniFileName, const gchar* dsnName, GHashTable* table) { FILE* stream; gchar* name; gchar* value; if ((stream = fopen (iniFileName, "r" )) != NULL ) { if (!FindSection (stream, dsnName)) { g_printerr ("Couldn't find DSN %s in %s\n", dsnName, iniFileName); fclose (stream); return 0; } else { while (GetNextItem (stream, &name, &value)) { g_hash_table_insert (table, strdup (name), strdup (value)); } } fclose( stream ); } return 1; } /* * Find the settings for the specified ODBC DSN */ gboolean LookupDSN (ConnectParams* params, const gchar* dsnName) { if (!params) { fprintf(stderr,"LookupDSN: no parameters, returning FALSE\n"); return FALSE; } /* * Set the DSN name property */ /* params->dsnName = g_string_assign (params->dsnName, dsnName); */ /* * Search for the ODBC ini file */ if (!(params->iniFileName = GetIniFileName ())) { fprintf(stderr,"LookupDSN: GetIniFileName returned FALSE\n"); return FALSE; } if (!LoadDSN (params->iniFileName->str, dsnName, params->table)) { fprintf(stderr,"LookupDSN: LoadDSN returned FALSE\n"); return FALSE; } return TRUE; } /* * Get the value of a given ODBC Connection Parameter */ gchar* GetConnectParam (ConnectParams* params, const gchar* paramName) { if (!params || !params->table) return NULL; return g_hash_table_lookup (params->table, paramName); } #else gboolean LookupDSN (ConnectParams* params, const gchar* dsnName) { return TRUE; } gchar* GetConnectParam (ConnectParams* params, const gchar* paramName) { static char tmp[FILENAME_MAX]; /* use old servername */ tmp[0] = '\0'; if (SQLGetPrivateProfileString(params->dsnName->str, paramName, "", tmp, FILENAME_MAX, "odbc.ini") > 0) { return tmp; } return NULL; } #endif /* !HAVE_SQLGETPRIVATEPROFILESTRING */ /* * Apply a connection string to the ODBC Parameter Settings */ void SetConnectString (ConnectParams* params, const gchar* connectString) { int end; char *cs, *s, *p, *name, *value; gpointer key; gpointer oldvalue; if (!params) return; /* * Make a copy of the connection string so we can modify it */ cs = (char *) g_strdup(connectString); s = cs; /* * Loop over ';' seperated name=value pairs */ p = strchr (s, '='); while (p) { if (p) *p = '\0'; /* * Extract name */ name = s; if (p) s = p + 1; /* * Extract value */ p = strchr (s, ';'); if (p) *p = '\0'; value = s; if (p) s = p + 1; /* * remove trailing spaces from name */ end = strlen (name) - 1; while (end > 0 && isspace(name[end])) name[end--] = '\0'; /* * remove leading spaces from value */ while (isspace(*value)) value++; if (g_hash_table_lookup_extended (params->table, name, &key, &oldvalue)) { /* * remove previous value */ g_hash_table_remove (params->table, key); /* * cleanup strings */ g_free (key); g_free (oldvalue); } /* * Insert the name/value pair into the hash table. * * Note that these g_strdup allocations are freed in cleanup, * which is called by FreeConnectParams. */ g_hash_table_insert (params->table, g_strdup (name), g_strdup (value)); p = strchr (s, '='); } g_free (cs); } /* * Dump all the ODBC Connection Paramters to a file (e.g. stdout) */ void DumpParams (ConnectParams* params, FILE* output) { if (!params) { g_printerr ("NULL ConnectionParams pointer\n"); return; } if (params->dsnName) g_printerr ("Parameter values for DSN: %s\n", params->dsnName->str); if (params->iniFileName) g_printerr ("Ini File is %s\n", params->iniFileName->str); g_hash_table_foreach (params->table, visit, output); } /* * Return the value of the DSN from the conneciton string */ gchar* ExtractDSN (ConnectParams* params, const gchar* connectString) { char *p, *q, *s; if (!params) return NULL; /* * Position ourselves to the beginning of "DSN" */ p = strstr (connectString, "DSN"); if (!p) return NULL; /* * Position ourselves to the "=" */ q = strchr (p, '='); if (!q) return NULL; /* * Skip over any leading spaces */ q++; while (isspace(*q)) q++; /* * Copy the DSN value to a buffer */ s = line; while (*q && *q != ';') *s++ = *q++; *s = '\0'; /* * Save it as a string in the params object */ params->dsnName = g_string_assign (params->dsnName, line); return params->dsnName->str; } gchar* ExtractDBQ (ConnectParams* params, const gchar* connectString) { char *p, *q, *s; if (!params) return NULL; /* * Position ourselves to the beginning of "DSN" */ p = strstr (connectString, "DBQ"); if (!p) return NULL; /* * Position ourselves to the "=" */ q = strchr (p, '='); if (!q) return NULL; /* * Skip over any leading spaces */ q++; while (isspace(*q)) q++; /* * Copy the DSN value to a buffer */ s = line; while (*q && *q != ';') *s++ = *q++; *s = '\0'; /* * Save it as a string in the params object */ params->dsnName = g_string_assign (params->dsnName, line); return params->dsnName->str; } /* * Begin local function definitions */ /* * Make a hash from all the characters */ static guint HashFunction (gconstpointer key) { guint value = 0; const char* s = key; while (*s) value += *s++; return value; } #if !HAVE_SQLGETPRIVATEPROFILESTRING static GString* GetIniFileName () { char* setting; GString* iniFileName = g_string_new (""); /* * First, try the ODBCINI environment variable */ if ((setting = getenv ("ODBCINI")) != NULL) { g_string_assign (iniFileName, getenv ("ODBCINI")); if (FileExists (iniFileName->str)) return iniFileName; g_string_assign (iniFileName, ""); } /* * Second, try the HOME environment variable */ if ((setting = getenv ("HOME")) != NULL) { g_string_assign (iniFileName, setting); iniFileName = g_string_append (iniFileName, "/.odbc.ini"); if (FileExists (iniFileName->str)) return iniFileName; g_string_assign (iniFileName, ""); } /* * As a last resort, try SYS_ODBC_INI */ g_string_assign (iniFileName, SYS_ODBC_INI); if (FileExists (iniFileName->str)) return iniFileName; g_string_assign (iniFileName, ""); return iniFileName; } static int FileExists (const gchar* name) { struct stat fileStat; return (stat (name, &fileStat) == 0); } static int FindSection (FILE* stream, const char* section) { char* s; char sectionPattern[max_line]; int len; strcpy (sectionPattern, "["); strcat (sectionPattern, section); strcat (sectionPattern, "]"); s = fgets (line, max_line, stream); while (s != NULL) { /* * Get rid of the newline character */ len = strlen (line); if (len > 0) line[strlen (line) - 1] = '\0'; /* * look for the section header */ if (strcmp (line, sectionPattern) == 0) return 1; s = fgets (line, max_line, stream); } return 0; } static int GetNextItem (FILE* stream, char** name, char** value) { char* s; int len; char equals[] = "="; /* used for seperator for strtok */ char* token; if (name == NULL || value == NULL) { g_printerr ("GetNextItem, invalid parameters"); return 0; } s = fgets (line, max_line, stream); if (s == NULL) { //perror ("fgets"); return 0; } /* * Get rid of the newline character */ len = strlen (line); if (len > 0) line[strlen (line) - 1] = '\0'; /* * Extract name from name = value */ if ((token = strtok (line, equals)) == NULL) return 0; len = strlen (token); while (len > 0 && isspace(token[len-1])) { len--; token[len] = '\0'; } *name = token; /* * extract value from name = value */ token = strtok (NULL, equals); if (token == NULL) return 0; while (*token && isspace(token[0])) token++; *value = token; return 1; } #endif //!HAVE_SQLGETPRIVATEPROFILESTRING static void visit (gpointer key, gpointer value, gpointer user_data) { FILE* output = (FILE*) user_data; fprintf(output, "Parameter: %s, Value: %s\n", (char*)key, (char*)value); } static gboolean cleanup (gpointer key, gpointer value, gpointer user_data) { g_free (key); g_free (value); return TRUE; } #ifdef UNIXODBC #include int ODBCINSTGetProperties(HODBCINSTPROPERTY hLastProperty) { hLastProperty->pNext = (HODBCINSTPROPERTY) malloc(sizeof(ODBCINSTPROPERTY)); hLastProperty = hLastProperty->pNext; memset(hLastProperty, 0, sizeof(ODBCINSTPROPERTY)); hLastProperty->nPromptType = ODBCINST_PROMPTTYPE_FILENAME; strncpy(hLastProperty->szName, "Database", INI_MAX_PROPERTY_NAME); strncpy(hLastProperty->szValue, "", INI_MAX_PROPERTY_VALUE); hLastProperty->pszHelp = (char *) strdup("Filename and Path of MDB file to connect to.\n" "Use the full path to the database file."); return 1; } #endif mdbtools-0.7.1/src/odbc/connectparams.h000066400000000000000000000030201222645741400200500ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _connectparams_h_ #define _connectparams_h_ #include typedef struct { GString* dsnName; GString* iniFileName; GHashTable* table; } ConnectParams; ConnectParams* NewConnectParams (); void FreeConnectParams (ConnectParams* params); gboolean LookupDSN (ConnectParams* params, const gchar* dsnName); gchar* GetConnectParam (ConnectParams* params, const gchar* paramName); void SetConnectString (ConnectParams* params, const gchar* connectString); void DumpParams (ConnectParams* params, FILE* output); gchar* ExtractDSN (ConnectParams* params, const gchar* connectString); gchar* ExtractDBQ (ConnectParams* params, const gchar* connectString); #endif mdbtools-0.7.1/src/odbc/mdbodbc.h000066400000000000000000000035611222645741400166170ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _mdbodbc_h_ #define _mdbodbc_h_ #include #include #if defined(UNIXODBC) # include #elif defined(IODBC) # include #endif #include "mdbtools.h" #include "mdbsql.h" #include "connectparams.h" #ifdef __cplusplus extern "C" { #endif struct _henv { MdbSQL *sql; GPtrArray *connections; }; struct _hdbc { struct _henv *henv; ConnectParams* params; GPtrArray *statements; }; struct _hstmt { struct _hdbc *hdbc; /* reminder to self: the following is here for testing purposes. * please make dynamic before checking in */ char query[4096]; struct _sql_bind_info *bind_head; int rows_affected; int icol; /* SQLGetData: last column */ int pos; /* SQLGetData: last position (truncated result) */ }; struct _sql_bind_info { int column_number; int column_bindtype; /* type/conversion required */ int column_bindlen; /* size of varaddr buffer */ int *column_lenbind; /* where to store length of varaddr used */ char *varaddr; struct _sql_bind_info *next; }; #ifdef __cplusplus } #endif #endif mdbtools-0.7.1/src/odbc/odbc.c000066400000000000000000002104211222645741400161220ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef ENABLE_ODBC_W #define SQL_NOUNICODEMAP #define UNICODE #endif //ENABLE_ODBC_W #include #include #include #include #include "mdbodbc.h" //#define TRACE(x) fprintf(stderr,"Function %s\n", x); #define TRACE(x) #ifdef ENABLE_ODBC_W static iconv_t iconv_in,iconv_out; #endif //ENABLE_ODBC_W static SQLSMALLINT _odbc_get_client_type(MdbColumn *col); static int _odbc_fix_literals(struct _hstmt *stmt); //static int _odbc_get_server_type(int clt_type); static int _odbc_get_string_size(int size, SQLCHAR *str); static SQLRETURN SQL_API _SQLAllocConnect(SQLHENV henv, SQLHDBC *phdbc); static SQLRETURN SQL_API _SQLAllocEnv(SQLHENV *phenv); static SQLRETURN SQL_API _SQLAllocStmt(SQLHDBC hdbc, SQLHSTMT *phstmt); static SQLRETURN SQL_API _SQLFreeConnect(SQLHDBC hdbc); static SQLRETURN SQL_API _SQLFreeEnv(SQLHENV henv); static SQLRETURN SQL_API _SQLFreeStmt(SQLHSTMT hstmt, SQLUSMALLINT fOption); static void bind_columns (struct _hstmt*); static void unbind_columns (struct _hstmt*); #define FILL_FIELD(f,v,s) mdb_fill_temp_field(f,v,s,0,0,0,0) #ifndef MIN #define MIN(a,b) (a>b ? b : a) #endif #define _MAX_ERROR_LEN 255 static char lastError[_MAX_ERROR_LEN+1]; static char sqlState[6]; typedef struct { SQLCHAR *type_name; SQLSMALLINT data_type; SQLINTEGER column_size; SQLCHAR *literal_prefix; SQLCHAR *literal_suffix; SQLCHAR *create_params; SQLSMALLINT nullable; SQLSMALLINT case_sensitive; SQLSMALLINT searchable; SQLSMALLINT *unsigned_attribute; SQLSMALLINT fixed_prec_scale; SQLSMALLINT auto_unique_value; SQLCHAR *local_type_name; SQLSMALLINT minimum_scale; SQLSMALLINT maximum_scale; SQLSMALLINT sql_data_type; SQLSMALLINT *sql_datetime_sub; SQLSMALLINT *num_prec_radix; SQLSMALLINT *interval_precision; } TypeInfo; TypeInfo type_info[] = { {(SQLCHAR*)"text", SQL_VARCHAR, 255, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_FALSE, NULL, 0, 255, SQL_VARCHAR, NULL, NULL, NULL}, {(SQLCHAR*)"memo", SQL_VARCHAR, 4096, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_FALSE, NULL, 0, 4096, SQL_VARCHAR, NULL, NULL, NULL}, {(SQLCHAR*)"text", SQL_CHAR, 255, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_FALSE, NULL, 0, 255, SQL_CHAR, NULL, NULL, NULL}, {(SQLCHAR*)"numeric", SQL_NUMERIC, 255, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_FALSE, NULL, 0, 255, SQL_NUMERIC, NULL, NULL, NULL}, {(SQLCHAR*)"numeric", SQL_DECIMAL, 255, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_FALSE, NULL, 0, 255, SQL_DECIMAL, NULL, NULL, NULL}, {(SQLCHAR*)"long integer", SQL_INTEGER, 4, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_TRUE, NULL, 0, 4, SQL_INTEGER, NULL, NULL, NULL}, {(SQLCHAR*)"integer", SQL_SMALLINT, 4, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_TRUE, NULL, 0, 4, SQL_SMALLINT, NULL, NULL, NULL}, {(SQLCHAR*)"integer", SQL_SMALLINT, 4, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_TRUE, NULL, 0, 4, SQL_SMALLINT, NULL, NULL, NULL}, {(SQLCHAR*)"single", SQL_REAL, 4, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_TRUE, NULL, 0, 4, SQL_REAL, NULL, NULL, NULL}, {(SQLCHAR*)"double", SQL_DOUBLE, 8, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_TRUE, NULL, 0, 8, SQL_FLOAT, NULL, NULL, NULL}, {(SQLCHAR*)"datetime", SQL_DATETIME, 8, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_TRUE, NULL, 0, 8, SQL_DATETIME, NULL, NULL, NULL} }; #define NUM_TYPE_INFO_COLS 19 #define MAX_TYPE_INFO 11 #ifdef ENABLE_ODBC_W void my_fini(); MDB_CONSTRUCTOR(my_init) { TRACE("my_init"); int endian = 1; const char* wcharset; if (sizeof(SQLWCHAR) == 2) if (*(char*)&endian == 1) wcharset = "UCS-2LE"; else wcharset = "UCS-2BE"; else if (sizeof(SQLWCHAR) == 4) if (*(char*)&endian == 1) wcharset = "UCS-4LE"; else wcharset = "UCS-4BE"; else fprintf(stderr, "Unsupported SQLWCHAR width %zd\n", sizeof(SQLWCHAR)); //fprintf(stderr,"charset %s\n", wcharset); //fprintf(stderr, "SQLWCHAR width %d\n", sizeof(SQLWCHAR)); /* #if __SIZEOF_WCHAR_T__ == 4 || __WCHAR_MAX__ > 0x10000 #define WCHAR_CHARSET "UCS-4LE" #else #define WCHAR_CHARSET "UCS-2LE" #endif */ iconv_out = iconv_open(wcharset, "UTF-8"); iconv_in = iconv_open("UTF-8", wcharset); atexit(my_fini); } void my_fini() { TRACE("my_fini"); if(iconv_out != (iconv_t)-1)iconv_close(iconv_out); if(iconv_in != (iconv_t)-1)iconv_close(iconv_in); } static int unicode2ascii(char *_in, size_t *_lin, char *_out, size_t *_lout){ char *in=_in, *out=_out; size_t lin=*_lin, lout=*_lout; int ret = iconv(iconv_in, &in, &lin, &out, &lout); *_lin -= lin; *_lout -= lout; return ret; } static int ascii2unicode(char *_in, size_t *_lin, char *_out, size_t *_lout){ //fprintf(stderr,"ascii2unicode %08x %08x %08x %08x\n",_in,_lin,_out,_lout); char *in=_in, *out=_out; size_t lin=*_lin, lout=*_lout; //fprintf(stderr,"ascii2unicode %zd %zd\n",lin,lout); int ret = iconv(iconv_out, &in, &lin, &out, &lout); *_lin -= lin; *_lout -= lout; return ret; } static int sqlwlen(SQLWCHAR *p){ int r=0; for(;*p;r++) p++; return r; } #endif // ENABLE_ODBC_W /* The SQL engine is presently non-reenterrant and non-thread safe. See _SQLExecute for details. */ static void LogError (const char* error) { /* * Someday, I might make this store more than one error. */ strncpy (lastError, error, _MAX_ERROR_LEN); lastError[_MAX_ERROR_LEN] = '\0'; /* in case we had a long message */ } static SQLRETURN do_connect ( SQLHDBC hdbc, char *database) { struct _hdbc *dbc = (struct _hdbc *) hdbc; struct _henv *env = (struct _henv *) dbc->henv; if (mdb_sql_open(env->sql, database)) return SQL_SUCCESS; else return SQL_ERROR; } static SQLRETURN SQL_API _SQLDriverConnect( SQLHDBC hdbc, SQLHWND hwnd, SQLCHAR *szConnStrIn, SQLSMALLINT cbConnStrIn, SQLCHAR *szConnStrOut, SQLSMALLINT cbConnStrOutMax, SQLSMALLINT *pcbConnStrOut, SQLUSMALLINT fDriverCompletion) { char* dsn = NULL; char* database = NULL; ConnectParams* params; SQLRETURN ret; TRACE("_SQLDriverConnect"); strcpy (lastError, ""); params = ((struct _hdbc*) hdbc)->params; if ((dsn = ExtractDSN (params, (gchar*)szConnStrIn))) { if (!LookupDSN (params, dsn)){ LogError ("Could not find DSN in odbc.ini"); return SQL_ERROR; } SetConnectString (params, (gchar*)szConnStrIn); if (!(database = GetConnectParam (params, "Database"))){ LogError ("Could not find Database parameter"); return SQL_ERROR; } ret = do_connect (hdbc, database); return ret; } if ((database = ExtractDBQ (params, (gchar*)szConnStrIn))) { ret = do_connect (hdbc, database); return ret; } LogError ("Could not find DSN nor DBQ in connect string"); return SQL_ERROR; } SQLRETURN SQL_API SQLDriverConnect( SQLHDBC hdbc, SQLHWND hwnd, SQLCHAR *szConnStrIn, SQLSMALLINT cbConnStrIn, SQLCHAR *szConnStrOut, SQLSMALLINT cbConnStrOutMax, SQLSMALLINT *pcbConnStrOut, SQLUSMALLINT fDriverCompletion) #ifdef HAVE_ATTRIBUTE_ALIAS __attribute__((alias("_SQLDriverConnect"))); #else { return _SQLDriverConnect(hdbc, hwnd, szConnStrIn, cbConnStrIn, szConnStrOut, cbConnStrOutMax, pcbConnStrOut, fDriverCompletion); } #endif #ifdef ENABLE_ODBC_W SQLRETURN SQL_API SQLDriverConnectW( SQLHDBC hdbc, SQLHWND hwnd, SQLWCHAR *szConnStrIn, SQLSMALLINT cbConnStrIn, SQLWCHAR *szConnStrOut, SQLSMALLINT cbConnStrOutMax, SQLSMALLINT *pcbConnStrOut, SQLUSMALLINT fDriverCompletion) { TRACE("SQLDriverConnectW"); if(cbConnStrIn==SQL_NTS)cbConnStrIn=sqlwlen(szConnStrIn); { size_t l = cbConnStrIn*sizeof(SQLWCHAR), z = (cbConnStrIn+1)*3; SQLCHAR *tmp = malloc(z); SQLRETURN ret; unicode2ascii((char*)szConnStrIn, &l, (char*)tmp, &z); tmp[z] = 0; ret = _SQLDriverConnect(hdbc,hwnd,tmp,SQL_NTS,NULL,0,pcbConnStrOut,fDriverCompletion); free(tmp); if (szConnStrOut && cbConnStrOutMax>0) szConnStrOut[0] = 0; if (pcbConnStrOut) *pcbConnStrOut = 0; return ret; } } #endif // ENABLE_ODBC_W SQLRETURN SQL_API SQLBrowseConnect( SQLHDBC hdbc, SQLCHAR *szConnStrIn, SQLSMALLINT cbConnStrIn, SQLCHAR *szConnStrOut, SQLSMALLINT cbConnStrOutMax, SQLSMALLINT *pcbConnStrOut) { TRACE("SQLBrowseConnect"); return SQL_SUCCESS; } SQLRETURN SQL_API SQLColumnPrivileges( SQLHSTMT hstmt, SQLCHAR *szCatalogName, SQLSMALLINT cbCatalogName, SQLCHAR *szSchemaName, SQLSMALLINT cbSchemaName, SQLCHAR *szTableName, SQLSMALLINT cbTableName, SQLCHAR *szColumnName, SQLSMALLINT cbColumnName) { TRACE("SQLColumnPrivileges"); return SQL_SUCCESS; } SQLRETURN SQL_API SQLDescribeParam( SQLHSTMT hstmt, SQLUSMALLINT ipar, SQLSMALLINT *pfSqlType, SQLULEN *pcbParamDef, SQLSMALLINT *pibScale, SQLSMALLINT *pfNullable) { TRACE("SQLDescribeParam"); return SQL_SUCCESS; } SQLRETURN SQL_API SQLExtendedFetch( SQLHSTMT hstmt, SQLUSMALLINT fFetchType, SQLLEN irow, SQLULEN *pcrow, SQLUSMALLINT *rgfRowStatus) { struct _hstmt *stmt = (struct _hstmt *) hstmt; struct _hdbc *dbc = (struct _hdbc *) stmt->hdbc; struct _henv *env = (struct _henv *) dbc->henv; TRACE("SQLExtendedFetch"); if (fFetchType!=SQL_FETCH_NEXT) { LogError("Fetch type not supported in SQLExtendedFetch"); return SQL_ERROR; } if (pcrow) *pcrow=1; if (rgfRowStatus) *rgfRowStatus = SQL_SUCCESS; /* what is the row status value? */ bind_columns(stmt); if (mdb_fetch_row(env->sql->cur_table)) { stmt->rows_affected++; return SQL_SUCCESS; } else { return SQL_NO_DATA_FOUND; } } SQLRETURN SQL_API SQLForeignKeys( SQLHSTMT hstmt, SQLCHAR *szPkCatalogName, SQLSMALLINT cbPkCatalogName, SQLCHAR *szPkSchemaName, SQLSMALLINT cbPkSchemaName, SQLCHAR *szPkTableName, SQLSMALLINT cbPkTableName, SQLCHAR *szFkCatalogName, SQLSMALLINT cbFkCatalogName, SQLCHAR *szFkSchemaName, SQLSMALLINT cbFkSchemaName, SQLCHAR *szFkTableName, SQLSMALLINT cbFkTableName) { TRACE("SQLForeignKeys"); return SQL_SUCCESS; } SQLRETURN SQL_API SQLMoreResults( SQLHSTMT hstmt) { TRACE("SQLMoreResults"); return SQL_NO_DATA; } SQLRETURN SQL_API SQLNativeSql( SQLHDBC hdbc, SQLCHAR *szSqlStrIn, SQLINTEGER cbSqlStrIn, SQLCHAR *szSqlStr, SQLINTEGER cbSqlStrMax, SQLINTEGER *pcbSqlStr) { TRACE("SQLNativeSql"); return SQL_SUCCESS; } SQLRETURN SQL_API SQLNumParams( SQLHSTMT hstmt, SQLSMALLINT *pcpar) { TRACE("SQLNumParams"); return SQL_SUCCESS; } SQLRETURN SQL_API SQLParamOptions( SQLHSTMT hstmt, SQLULEN crow, SQLULEN *pirow) { TRACE("SQLParamOptions"); return SQL_SUCCESS; } SQLRETURN SQL_API SQLPrimaryKeys( SQLHSTMT hstmt, SQLCHAR *szCatalogName, SQLSMALLINT cbCatalogName, SQLCHAR *szSchemaName, SQLSMALLINT cbSchemaName, SQLCHAR *szTableName, SQLSMALLINT cbTableName) { TRACE("SQLPrimaryKeys"); return SQL_SUCCESS; } SQLRETURN SQL_API SQLProcedureColumns( SQLHSTMT hstmt, SQLCHAR *szCatalogName, SQLSMALLINT cbCatalogName, SQLCHAR *szSchemaName, SQLSMALLINT cbSchemaName, SQLCHAR *szProcName, SQLSMALLINT cbProcName, SQLCHAR *szColumnName, SQLSMALLINT cbColumnName) { TRACE("SQLProcedureColumns"); return SQL_SUCCESS; } SQLRETURN SQL_API SQLProcedures( SQLHSTMT hstmt, SQLCHAR *szCatalogName, SQLSMALLINT cbCatalogName, SQLCHAR *szSchemaName, SQLSMALLINT cbSchemaName, SQLCHAR *szProcName, SQLSMALLINT cbProcName) { TRACE("SQLProcedures"); return SQL_SUCCESS; } SQLRETURN SQL_API SQLSetPos( SQLHSTMT hstmt, SQLSETPOSIROW irow, SQLUSMALLINT fOption, SQLUSMALLINT fLock) { TRACE("SQLSetPos"); return SQL_SUCCESS; } SQLRETURN SQL_API SQLTablePrivileges( SQLHSTMT hstmt, SQLCHAR *szCatalogName, SQLSMALLINT cbCatalogName, SQLCHAR *szSchemaName, SQLSMALLINT cbSchemaName, SQLCHAR *szTableName, SQLSMALLINT cbTableName) { TRACE("SQLTablePrivileges"); return SQL_SUCCESS; } SQLRETURN SQL_API SQLDrivers( SQLHENV henv, SQLUSMALLINT fDirection, SQLCHAR *szDriverDesc, SQLSMALLINT cbDriverDescMax, SQLSMALLINT *pcbDriverDesc, SQLCHAR *szDriverAttributes, SQLSMALLINT cbDrvrAttrMax, SQLSMALLINT *pcbDrvrAttr) { TRACE("SQLDrivers"); return SQL_SUCCESS; } SQLRETURN SQL_API SQLSetEnvAttr ( SQLHENV EnvironmentHandle, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER StringLength) { TRACE("SQLSetEnvAttr"); return SQL_SUCCESS; } SQLRETURN SQL_API SQLBindParameter( SQLHSTMT hstmt, SQLUSMALLINT ipar, SQLSMALLINT fParamType, SQLSMALLINT fCType, SQLSMALLINT fSqlType, SQLULEN cbColDef, SQLSMALLINT ibScale, SQLPOINTER rgbValue, SQLLEN cbValueMax, SQLLEN *pcbValue) { /*struct _hstmt *stmt;*/ TRACE("SQLBindParameter"); /*stmt = (struct _hstmt *) hstmt;*/ return SQL_SUCCESS; } SQLRETURN SQL_API SQLAllocHandle( SQLSMALLINT HandleType, SQLHANDLE InputHandle, SQLHANDLE * OutputHandle) { TRACE("SQLAllocHandle"); switch(HandleType) { case SQL_HANDLE_STMT: return _SQLAllocStmt(InputHandle,OutputHandle); break; case SQL_HANDLE_DBC: return _SQLAllocConnect(InputHandle,OutputHandle); break; case SQL_HANDLE_ENV: return _SQLAllocEnv(OutputHandle); break; } return SQL_ERROR; } static SQLRETURN SQL_API _SQLAllocConnect( SQLHENV henv, SQLHDBC *phdbc) { struct _henv *env; struct _hdbc* dbc; TRACE("_SQLAllocConnect"); env = (struct _henv *) henv; dbc = (SQLHDBC) g_malloc0(sizeof(struct _hdbc)); dbc->henv=env; g_ptr_array_add(env->connections, dbc); dbc->params = NewConnectParams (); dbc->statements = g_ptr_array_new(); *phdbc=dbc; return SQL_SUCCESS; } SQLRETURN SQL_API SQLAllocConnect( SQLHENV henv, SQLHDBC *phdbc) { TRACE("SQLAllocConnect"); return _SQLAllocConnect(henv, phdbc); } static SQLRETURN SQL_API _SQLAllocEnv( SQLHENV *phenv) { struct _henv *env; TRACE("_SQLAllocEnv"); env = (SQLHENV) g_malloc0(sizeof(struct _henv)); env->sql = mdb_sql_init(); env->connections = g_ptr_array_new(); *phenv=env; return SQL_SUCCESS; } SQLRETURN SQL_API SQLAllocEnv( SQLHENV *phenv) { TRACE("SQLAllocEnv"); return _SQLAllocEnv(phenv); } static SQLRETURN SQL_API _SQLAllocStmt( SQLHDBC hdbc, SQLHSTMT *phstmt) { struct _hdbc *dbc; struct _hstmt *stmt; TRACE("_SQLAllocStmt"); dbc = (struct _hdbc *) hdbc; stmt = (SQLHSTMT) g_malloc0(sizeof(struct _hstmt)); stmt->hdbc=dbc; g_ptr_array_add(dbc->statements, stmt); *phstmt = stmt; return SQL_SUCCESS; } SQLRETURN SQL_API SQLAllocStmt( SQLHDBC hdbc, SQLHSTMT *phstmt) { TRACE("SQLAllocStmt"); return _SQLAllocStmt(hdbc,phstmt); } SQLRETURN SQL_API SQLBindCol( SQLHSTMT hstmt, SQLUSMALLINT icol, SQLSMALLINT fCType, SQLPOINTER rgbValue, SQLLEN cbValueMax, SQLLEN *pcbValue) { struct _hstmt *stmt = (struct _hstmt *) hstmt; struct _sql_bind_info *cur, *newitem; TRACE("SQLBindCol"); /* find available item in list */ cur = stmt->bind_head; while (cur) { if (cur->column_number==icol) break; cur = cur->next; } /* if this is a repeat */ if (cur) { cur->column_bindtype = fCType; cur->column_lenbind = (int *)pcbValue; cur->column_bindlen = cbValueMax; cur->varaddr = (char *) rgbValue; } else { /* didn't find it create a new one */ newitem = (struct _sql_bind_info *) g_malloc0(sizeof(struct _sql_bind_info)); newitem->column_number = icol; newitem->column_bindtype = fCType; newitem->column_bindlen = cbValueMax; newitem->column_lenbind = (int *)pcbValue; newitem->varaddr = (char *) rgbValue; /* if there's no head yet */ if (! stmt->bind_head) { stmt->bind_head = newitem; } else { /* find the tail of the list */ cur = stmt->bind_head; while (cur->next) { cur = cur->next; } cur->next = newitem; } } return SQL_SUCCESS; } SQLRETURN SQL_API SQLCancel( SQLHSTMT hstmt) { TRACE("SQLCancel"); return SQL_SUCCESS; } static SQLRETURN SQL_API _SQLConnect( SQLHDBC hdbc, SQLCHAR *szDSN, SQLSMALLINT cbDSN, SQLCHAR *szUID, SQLSMALLINT cbUID, SQLCHAR *szAuthStr, SQLSMALLINT cbAuthStr) { char* database = NULL; ConnectParams* params; SQLRETURN ret; TRACE("_SQLConnect"); strcpy (lastError, ""); params = ((struct _hdbc*) hdbc)->params; params->dsnName = g_string_assign (params->dsnName, (gchar*)szDSN); if (!LookupDSN (params, (gchar*)szDSN)) { LogError ("Could not find DSN in odbc.ini"); return SQL_ERROR; } else if (!(database = GetConnectParam (params, "Database"))) { LogError ("Could not find Database parameter"); return SQL_ERROR; } ret = do_connect (hdbc, database); return ret; } SQLRETURN SQL_API SQLConnect( SQLHDBC hdbc, SQLCHAR *szDSN, SQLSMALLINT cbDSN, SQLCHAR *szUID, SQLSMALLINT cbUID, SQLCHAR *szAuthStr, SQLSMALLINT cbAuthStr) #ifdef HAVE_ATTRIBUTE_ALIAS __attribute__((alias("_SQLConnect"))); #else { return _SQLConnect(hdbc, szDSN, cbDSN, szUID, cbUID, szAuthStr, cbAuthStr); } #endif #ifdef ENABLE_ODBC_W SQLRETURN SQL_API SQLConnectW( SQLHDBC hdbc, SQLWCHAR *szDSN, SQLSMALLINT cbDSN, SQLWCHAR *szUID, SQLSMALLINT cbUID, SQLWCHAR *szAuthStr, SQLSMALLINT cbAuthStr) { if(cbDSN==SQL_NTS)cbDSN=sqlwlen(szDSN); if(cbUID==SQL_NTS)cbUID=sqlwlen(szUID); if(cbAuthStr==SQL_NTS)cbAuthStr=sqlwlen(szAuthStr); { SQLCHAR *tmp1=calloc(cbDSN*4,1),*tmp2=calloc(cbUID*4,1),*tmp3=calloc(cbAuthStr*4,1); size_t l1=cbDSN*4,z1=cbDSN*2; size_t l2=cbUID*4,z2=cbUID*2; size_t l3=cbAuthStr*4,z3=cbAuthStr*2; SQLRETURN ret; unicode2ascii((char*)szDSN, &z1, (char*)tmp1, &l1); unicode2ascii((char*)szUID, &z2, (char*)tmp2, &l2); unicode2ascii((char*)szAuthStr, &z3, (char*)tmp3, &l3); ret = SQLConnect(hdbc, tmp1, l1, tmp2, l2, tmp3, l3); free(tmp1),free(tmp2),free(tmp3); return ret; } } #endif //ENABLE_ODBC_W static SQLRETURN SQL_API _SQLDescribeCol( SQLHSTMT hstmt, SQLUSMALLINT icol, SQLCHAR *szColName, SQLSMALLINT cbColNameMax, SQLSMALLINT *pcbColName, SQLSMALLINT *pfSqlType, SQLULEN *pcbColDef, /* precision */ SQLSMALLINT *pibScale, SQLSMALLINT *pfNullable) { int namelen, i; struct _hstmt *stmt = (struct _hstmt *) hstmt; struct _hdbc *dbc = (struct _hdbc *) stmt->hdbc; struct _henv *env = (struct _henv *) dbc->henv; MdbSQL *sql = env->sql; MdbSQLColumn *sqlcol; MdbColumn *col; MdbTableDef *table; SQLRETURN ret; TRACE("_SQLDescribeCol"); if (icol<1 || icol>sql->num_columns) { strcpy(sqlState, "07009"); // Invalid descriptor index return SQL_ERROR; } sqlcol = g_ptr_array_index(sql->columns,icol - 1); table = sql->cur_table; for (i=0;inum_cols;i++) { col=g_ptr_array_index(table->columns,i); if (!strcasecmp(sqlcol->name, col->name)) { break; } } if (i==table->num_cols) { fprintf(stderr, "Column %s lost\n", (char*)sqlcol->name); strcpy(sqlState, "07009"); // Invalid descriptor index return SQL_ERROR; } ret = SQL_SUCCESS; namelen = strlen(sqlcol->name); if (pcbColName) *pcbColName=namelen; if (szColName) { if (cbColNameMax < 0) { strcpy(sqlState, "HY090"); // Invalid string or buffer length return SQL_ERROR; } if (namelen + 1 < cbColNameMax) { // Including \0 strcpy((char*)szColName, sqlcol->name); } else { if (cbColNameMax > 1) { strncpy((char*)szColName, sqlcol->name, cbColNameMax-1); szColName[cbColNameMax-1] = '\0'; } // So there is no \0 if cbColNameMax was 0 strcpy(sqlState, "01004"); // String data, right truncated ret = SQL_SUCCESS_WITH_INFO; } } if (pfSqlType) { *pfSqlType = _odbc_get_client_type(col); } if (pcbColDef) { *pcbColDef = col->col_size; } if (pibScale) { /* FIX ME */ *pibScale = 0; } if (pfNullable) { *pfNullable = !col->is_fixed; } return ret; } SQLRETURN SQL_API SQLDescribeCol( SQLHSTMT hstmt, SQLUSMALLINT icol, SQLCHAR *szColName, SQLSMALLINT cbColNameMax, SQLSMALLINT *pcbColName, SQLSMALLINT *pfSqlType, SQLULEN *pcbColDef, /* precision */ SQLSMALLINT *pibScale, SQLSMALLINT *pfNullable) #ifdef HAVE_ATTRIBUTE_ALIAS __attribute__((alias("_SQLDescribeCol"))); #else { return _SQLDescribeCol(hstmt, icol, szColName, cbColNameMax, pcbColName, pfSqlType, pcbColDef, pibScale, pfNullable); } #endif #ifdef ENABLE_ODBC_W SQLRETURN SQL_API SQLDescribeColW( SQLHSTMT hstmt, SQLUSMALLINT icol, SQLWCHAR *szColName, SQLSMALLINT cbColNameMax, SQLSMALLINT *pcbColName, SQLSMALLINT *pfSqlType, SQLULEN *pcbColDef, /* precision */ SQLSMALLINT *pibScale, SQLSMALLINT *pfNullable) { if(cbColNameMax==SQL_NTS)cbColNameMax=sqlwlen(szColName); { SQLCHAR *tmp=calloc(cbColNameMax*4,1); size_t l=cbColNameMax*4; SQLRETURN ret = _SQLDescribeCol(hstmt, icol, tmp, cbColNameMax*4, (SQLSMALLINT*)&l, pfSqlType, pcbColDef, pibScale, pfNullable); ascii2unicode((char*)tmp, &l, (char*)szColName, (size_t*)pcbColName); *pcbColName/=sizeof(SQLWCHAR); free(tmp); return ret; } } #endif //ENABLE_ODBC_W static SQLRETURN SQL_API _SQLColAttributes( SQLHSTMT hstmt, SQLUSMALLINT icol, SQLUSMALLINT fDescType, SQLPOINTER rgbDesc, SQLSMALLINT cbDescMax, SQLSMALLINT *pcbDesc, SQLLEN *pfDesc) { int namelen, i; struct _hstmt *stmt; struct _hdbc *dbc; struct _henv *env; MdbSQL *sql; MdbSQLColumn *sqlcol; MdbColumn *col; MdbTableDef *table; SQLRETURN ret; TRACE("_SQLColAttributes"); stmt = (struct _hstmt *) hstmt; dbc = (struct _hdbc *) stmt->hdbc; env = (struct _henv *) dbc->henv; sql = env->sql; /* dont check column index for these */ switch(fDescType) { case SQL_COLUMN_COUNT: case SQL_DESC_COUNT: *pfDesc = env->sql->num_columns; return SQL_SUCCESS; break; } if (icol<1 || icol>sql->num_columns) { strcpy(sqlState, "07009"); // Invalid descriptor index return SQL_ERROR; } /* find the column */ sqlcol = g_ptr_array_index(sql->columns,icol - 1); table = sql->cur_table; for (i=0;inum_cols;i++) { col=g_ptr_array_index(table->columns,i); if (!strcasecmp(sqlcol->name, col->name)) { break; } } if (i==table->num_cols) { strcpy(sqlState, "07009"); // Invalid descriptor index return SQL_ERROR; } // fprintf(stderr,"fDescType = %d\n", fDescType); ret = SQL_SUCCESS; switch(fDescType) { case SQL_COLUMN_NAME: case SQL_DESC_NAME: case SQL_COLUMN_LABEL: /* = SQL_DESC_LABEL */ if (cbDescMax < 0) { strcpy(sqlState, "HY090"); // Invalid string or buffer length return SQL_ERROR; } namelen = strlen(sqlcol->name); if (namelen + 1 < cbDescMax) { strcpy(rgbDesc, sqlcol->name); } else { if (cbDescMax > 1) { strncpy(rgbDesc, sqlcol->name, cbDescMax-1); ((char*)rgbDesc)[cbDescMax-1] = '\0'; } // So there is no \0 if cbDescMax was 0 strcpy(sqlState, "01004"); // String data, right truncated ret = SQL_SUCCESS_WITH_INFO; } break; case SQL_COLUMN_TYPE: /* =SQL_DESC_CONCISE_TYPE */ //*pfDesc = SQL_CHAR; *pfDesc = _odbc_get_client_type(col); break; case SQL_COLUMN_LENGTH: break; case SQL_COLUMN_DISPLAY_SIZE: /* =SQL_DESC_DISPLAY_SIZE */ *pfDesc = mdb_col_disp_size(col); break; default: strcpy(sqlState, "HYC00"); // Driver not capable ret = SQL_ERROR; break; } return ret; } SQLRETURN SQL_API SQLColAttributes( SQLHSTMT hstmt, SQLUSMALLINT icol, SQLUSMALLINT fDescType, SQLPOINTER rgbDesc, SQLSMALLINT cbDescMax, SQLSMALLINT *pcbDesc, SQLLEN *pfDesc) #ifdef HAVE_ATTRIBUTE_ALIAS __attribute__((alias("_SQLColAttributes"))); #else { return _SQLColAttributes(hstmt, icol, fDescType, rgbDesc, cbDescMax, pcbDesc, pfDesc); } #endif #ifdef ENABLE_ODBC_W SQLRETURN SQL_API SQLColAttributesW( SQLHSTMT hstmt, SQLUSMALLINT icol, SQLUSMALLINT fDescType, SQLPOINTER rgbDesc, SQLSMALLINT cbDescMax, SQLSMALLINT *pcbDesc, SQLLEN *pfDesc) { if (fDescType!=SQL_COLUMN_NAME && fDescType!=SQL_COLUMN_LABEL) return _SQLColAttributes(hstmt,icol,fDescType,rgbDesc,cbDescMax,pcbDesc,pfDesc); else{ SQLCHAR *tmp=calloc(cbDescMax*4,1); size_t l=cbDescMax*4; SQLRETURN ret=_SQLColAttributes(hstmt,icol,fDescType,tmp,cbDescMax*4,(SQLSMALLINT*)&l,pfDesc); ascii2unicode((char*)tmp, &l, (char*)rgbDesc, (size_t*)pcbDesc); *pcbDesc/=sizeof(SQLWCHAR); free(tmp); return ret; } } #endif //ENABLE_ODBC_W SQLRETURN SQL_API SQLDisconnect( SQLHDBC hdbc) { struct _hdbc *dbc; struct _henv *env; TRACE("SQLDisconnect"); dbc = (struct _hdbc *) hdbc; env = (struct _henv *) dbc->henv; // Automatically close all statements: while (dbc->statements->len) _SQLFreeStmt(g_ptr_array_index(dbc->statements, 0), SQL_DROP); mdb_sql_close(env->sql); return SQL_SUCCESS; } static SQLRETURN SQL_API _SQLError( SQLHENV henv, SQLHDBC hdbc, SQLHSTMT hstmt, SQLCHAR *szSqlState, SQLINTEGER *pfNativeError, SQLCHAR *szErrorMsg, SQLSMALLINT cbErrorMsgMax, SQLSMALLINT *pcbErrorMsg) { SQLRETURN result = SQL_NO_DATA_FOUND; TRACE("_SQLError"); //if(pfNativeError)fprintf(stderr,"NativeError %05d\n", *pfNativeError); if (strlen (lastError) > 0) { strcpy ((char*)szSqlState, "08001"); strcpy ((char*)szErrorMsg, lastError); if (pcbErrorMsg) *pcbErrorMsg = strlen (lastError); if (pfNativeError) *pfNativeError = 1; result = SQL_SUCCESS; strcpy (lastError, ""); } return result; } SQLRETURN SQL_API SQLError( SQLHENV henv, SQLHDBC hdbc, SQLHSTMT hstmt, SQLCHAR *szSqlState, SQLINTEGER *pfNativeError, SQLCHAR *szErrorMsg, SQLSMALLINT cbErrorMsgMax, SQLSMALLINT *pcbErrorMsg) #ifdef HAVE_ATTRIBUTE_ALIAS __attribute__((alias("_SQLError"))); #else { return _SQLError(henv, hdbc, hstmt, szSqlState, pfNativeError, szErrorMsg, cbErrorMsgMax, pcbErrorMsg); } #endif #ifdef ENABLE_ODBC_W SQLRETURN SQL_API SQLErrorW( SQLHENV henv, SQLHDBC hdbc, SQLHSTMT hstmt, SQLWCHAR *szSqlState, SQLINTEGER *pfNativeError, SQLWCHAR *szErrorMsg, SQLSMALLINT cbErrorMsgMax, SQLSMALLINT *pcbErrorMsg) { SQLCHAR szSqlState8[6]; SQLCHAR szErrorMsg8[3*cbErrorMsgMax+1]; SQLSMALLINT pcbErrorMsg8; SQLRETURN result; TRACE("SQLErrorW"); result = _SQLError(henv, hdbc, hstmt, szSqlState8, pfNativeError, szErrorMsg8, 3*cbErrorMsgMax+1, &pcbErrorMsg8); if (result == SQL_SUCCESS) { size_t l=6, z=6*sizeof(SQLWCHAR); ascii2unicode((char*)szSqlState8, &l, (char*)szSqlState, &z); l = cbErrorMsgMax; ascii2unicode((char*)szErrorMsg8, (size_t*)&pcbErrorMsg8, (char*)szErrorMsg, &l); if (pcbErrorMsg) *pcbErrorMsg = l; } return result; } #endif // ENABLE_ODBC_W static SQLRETURN SQL_API _SQLExecute( SQLHSTMT hstmt) { struct _hstmt *stmt = (struct _hstmt *) hstmt; struct _hdbc *dbc = (struct _hdbc *) stmt->hdbc; struct _henv *env = (struct _henv *) dbc->henv; TRACE("_SQLExecute"); /* fprintf(stderr,"query = %s\n",stmt->query); */ _odbc_fix_literals(stmt); mdb_sql_reset(env->sql); mdb_sql_run_query(env->sql, stmt->query); if (mdb_sql_has_error(env->sql)) { LogError("Couldn't parse SQL\n"); mdb_sql_reset(env->sql); return SQL_ERROR; } else { return SQL_SUCCESS; } } static SQLRETURN SQL_API _SQLExecDirect( SQLHSTMT hstmt, SQLCHAR *szSqlStr, SQLINTEGER cbSqlStr) { struct _hstmt *stmt = (struct _hstmt *) hstmt; TRACE("_SQLExecDirect"); strcpy(stmt->query, (char*)szSqlStr); return _SQLExecute(hstmt); } SQLRETURN SQL_API SQLExecDirect( SQLHSTMT hstmt, SQLCHAR *szSqlStr, SQLINTEGER cbSqlStr) #ifdef HAVE_ATTRIBUTE_ALIAS __attribute__((alias("_SQLExecDirect"))); #else { return _SQLExecDirect(hstmt, szSqlStr, cbSqlStr); } #endif #ifdef ENABLE_ODBC_W SQLRETURN SQL_API SQLExecDirectW( SQLHSTMT hstmt, SQLWCHAR *szSqlStr, SQLINTEGER cbSqlStr) { TRACE("SQLExecDirectW"); if(cbSqlStr==SQL_NTS)cbSqlStr=sqlwlen(szSqlStr); { SQLCHAR *tmp=calloc(cbSqlStr*4,1); size_t l=cbSqlStr*4,z=cbSqlStr*2; SQLRETURN ret; unicode2ascii((char*)szSqlStr, &z, (char*)tmp, &l); ret = _SQLExecDirect(hstmt, tmp, l); TRACE("SQLExecDirectW end"); free(tmp); return ret; } } #endif // ENABLE_ODBC_W SQLRETURN SQL_API SQLExecute( SQLHSTMT hstmt) { TRACE("SQLExecute"); return _SQLExecute(hstmt); } static void bind_columns(struct _hstmt *stmt) { struct _hdbc *dbc = (struct _hdbc *) stmt->hdbc; struct _henv *env = (struct _henv *) dbc->henv; struct _sql_bind_info *cur; TRACE("bind_columns"); if (stmt->rows_affected==0) { cur = stmt->bind_head; while (cur) { if (cur->column_number>0 && cur->column_number <= env->sql->num_columns) { mdb_sql_bind_column(env->sql, cur->column_number, cur->varaddr, cur->column_lenbind); } else { /* log error ? */ } cur = cur->next; } } } static void unbind_columns(struct _hstmt *stmt) { struct _sql_bind_info *cur, *next; TRACE("unbind_columns"); //Free the memory allocated for bound columns cur = stmt->bind_head; while(cur) { next = cur->next; g_free(cur); cur = next; } stmt->bind_head = NULL; } SQLRETURN SQL_API SQLFetch( SQLHSTMT hstmt) { struct _hstmt *stmt = (struct _hstmt *) hstmt; struct _hdbc *dbc = (struct _hdbc *) stmt->hdbc; struct _henv *env = (struct _henv *) dbc->henv; TRACE("SQLFetch"); /* if we bound columns, transfer them to res_info now that we have one */ bind_columns(stmt); //cur = stmt->bind_head; //while (cur) { //if (cur->column_number>0 && //cur->column_number <= env->sql->num_columns) { // if (cur->column_lenbind) *(cur->column_lenbind) = 4; //} //cur = cur->next; //} if (mdb_fetch_row(env->sql->cur_table)) { stmt->rows_affected++; return SQL_SUCCESS; } else { return SQL_NO_DATA_FOUND; } } SQLRETURN SQL_API SQLFreeHandle( SQLSMALLINT HandleType, SQLHANDLE Handle) { TRACE("SQLFreeHandle"); switch(HandleType) { case SQL_HANDLE_STMT: _SQLFreeStmt(Handle,SQL_DROP); break; case SQL_HANDLE_DBC: _SQLFreeConnect(Handle); break; case SQL_HANDLE_ENV: _SQLFreeEnv(Handle); break; } return SQL_SUCCESS; } static SQLRETURN SQL_API _SQLFreeConnect( SQLHDBC hdbc) { struct _hdbc* dbc = (struct _hdbc*) hdbc; struct _henv* env; TRACE("_SQLFreeConnect"); env = dbc->henv; if (dbc->statements->len) { // Function sequence error strcpy(sqlState, "HY010"); return SQL_ERROR; } if (!g_ptr_array_remove(env->connections, dbc)) return SQL_INVALID_HANDLE; FreeConnectParams(dbc->params); g_ptr_array_free(dbc->statements, TRUE); g_free(dbc); return SQL_SUCCESS; } SQLRETURN SQL_API SQLFreeConnect( SQLHDBC hdbc) { TRACE("SQLFreeConnect"); return _SQLFreeConnect(hdbc); } static SQLRETURN SQL_API _SQLFreeEnv( SQLHENV henv) { struct _henv* env = (struct _henv*)henv; TRACE("_SQLFreeEnv"); if (env->connections->len) { // Function sequence error strcpy(sqlState, "HY010"); return SQL_ERROR; } g_ptr_array_free(env->connections, TRUE); return SQL_SUCCESS; } SQLRETURN SQL_API SQLFreeEnv( SQLHENV henv) { TRACE("SQLFreeEnv"); return _SQLFreeEnv(henv); } static SQLRETURN SQL_API _SQLFreeStmt( SQLHSTMT hstmt, SQLUSMALLINT fOption) { struct _hstmt *stmt=(struct _hstmt *)hstmt; struct _hdbc *dbc = (struct _hdbc *) stmt->hdbc; struct _henv *env = (struct _henv *) dbc->henv; MdbSQL *sql = env->sql; TRACE("_SQLFreeStmt"); if (fOption==SQL_DROP) { if (!g_ptr_array_remove(dbc->statements, stmt)) return SQL_INVALID_HANDLE; mdb_sql_reset(sql); unbind_columns(stmt); g_free(stmt); } else if (fOption==SQL_CLOSE) { stmt->rows_affected = 0; } else if (fOption==SQL_UNBIND) { unbind_columns(stmt); } else if (fOption==SQL_RESET_PARAMS) { /* Bound parameters not currently implemented */ } else { } return SQL_SUCCESS; } SQLRETURN SQL_API SQLFreeStmt( SQLHSTMT hstmt, SQLUSMALLINT fOption) { TRACE("SQLFreeStmt"); return _SQLFreeStmt(hstmt, fOption); } SQLRETURN SQL_API SQLGetStmtAttr ( SQLHSTMT StatementHandle, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER BufferLength, SQLINTEGER * StringLength) { TRACE("SQLGetStmtAttr"); return SQL_SUCCESS; } SQLRETURN SQL_API SQLGetCursorName( SQLHSTMT hstmt, SQLCHAR *szCursor, SQLSMALLINT cbCursorMax, SQLSMALLINT *pcbCursor) { TRACE("SQLGetCursorName"); return SQL_SUCCESS; } SQLRETURN SQL_API SQLNumResultCols( SQLHSTMT hstmt, SQLSMALLINT *pccol) { struct _hstmt *stmt = (struct _hstmt *) hstmt; struct _hdbc *dbc = (struct _hdbc *) stmt->hdbc; struct _henv *env = (struct _henv *) dbc->henv; TRACE("SQLNumResultCols"); *pccol = env->sql->num_columns; return SQL_SUCCESS; } SQLRETURN SQL_API SQLPrepare( SQLHSTMT hstmt, SQLCHAR *szSqlStr, SQLINTEGER cbSqlStr) { struct _hstmt *stmt=(struct _hstmt *)hstmt; int sqllen = _odbc_get_string_size(cbSqlStr, szSqlStr); TRACE("SQLPrepare"); strncpy(stmt->query, (char*)szSqlStr, sqllen); stmt->query[sqllen]='\0'; return SQL_SUCCESS; } SQLRETURN SQL_API SQLRowCount( SQLHSTMT hstmt, SQLLEN *pcrow) { struct _hstmt *stmt=(struct _hstmt *)hstmt; TRACE("SQLRowCount"); *pcrow = stmt->rows_affected; return SQL_SUCCESS; } SQLRETURN SQL_API SQLSetCursorName( SQLHSTMT hstmt, SQLCHAR *szCursor, SQLSMALLINT cbCursor) { TRACE("SQLSetCursorName"); return SQL_SUCCESS; } SQLRETURN SQL_API SQLTransact( SQLHENV henv, SQLHDBC hdbc, SQLUSMALLINT fType) { TRACE("SQLTransact"); return SQL_SUCCESS; } SQLRETURN SQL_API SQLSetParam( /* Use SQLBindParameter */ SQLHSTMT hstmt, SQLUSMALLINT ipar, SQLSMALLINT fCType, SQLSMALLINT fSqlType, SQLULEN cbParamDef, SQLSMALLINT ibScale, SQLPOINTER rgbValue, SQLLEN *pcbValue) { TRACE("SQLSetParam"); return SQL_SUCCESS; } static SQLRETURN SQL_API _SQLColumns( SQLHSTMT hstmt, SQLCHAR *szCatalogName, SQLSMALLINT cbCatalogName, SQLCHAR *szSchemaName, SQLSMALLINT cbSchemaName, SQLCHAR *szTableName, SQLSMALLINT cbTableName, SQLCHAR *szColumnName, SQLSMALLINT cbColumnName) { struct _hstmt *stmt = (struct _hstmt *) hstmt; struct _hdbc *dbc = (struct _hdbc *) stmt->hdbc; struct _henv *env = (struct _henv *) dbc->henv; MdbSQL *sql = env->sql; MdbHandle *mdb = sql->mdb; MdbTableDef *ttable; MdbField fields[18]; unsigned char row_buffer[MDB_PGSIZE]; int row_size; unsigned int i, j, k; MdbCatalogEntry *entry; MdbTableDef *table; MdbColumn *col; unsigned int ts2, ts3, ts5; unsigned char t2[MDB_BIND_SIZE], t3[MDB_BIND_SIZE], t5[MDB_BIND_SIZE]; SQLSMALLINT nullable; /* SQL_NULLABLE or SQL_NO_NULLS */ SQLSMALLINT datatype; /* For datetime, use concise data type */ SQLSMALLINT sqldatatype; /* For datetime, use nonconcise data type */ SQLINTEGER ordinal; TRACE("_SQLColumns"); mdb_read_catalog(mdb, MDB_ANY); ttable = mdb_create_temp_table(mdb, "#columns"); mdb_sql_add_temp_col(sql, ttable, 0, "TABLE_CAT", MDB_TEXT, 128, 0); mdb_sql_add_temp_col(sql, ttable, 1, "TABLE_SCHEM", MDB_TEXT, 128, 0); mdb_sql_add_temp_col(sql, ttable, 2, "TABLE_NAME", MDB_TEXT, 128, 0); mdb_sql_add_temp_col(sql, ttable, 3, "COLUMN_NAME", MDB_TEXT, 128, 0); mdb_sql_add_temp_col(sql, ttable, 4, "DATA_TYPE", MDB_INT, 0, 1); mdb_sql_add_temp_col(sql, ttable, 5, "TYPE_NAME", MDB_TEXT, 128, 0); mdb_sql_add_temp_col(sql, ttable, 6, "COLUMN_SIZE", MDB_LONGINT, 0, 1); mdb_sql_add_temp_col(sql, ttable, 7, "BUFFER_LENGTH", MDB_LONGINT, 0, 1); mdb_sql_add_temp_col(sql, ttable, 8, "DECIMAL_DIGITS", MDB_INT, 0, 1); mdb_sql_add_temp_col(sql, ttable, 9, "NUM_PREC_RADIX", MDB_INT, 0, 1); mdb_sql_add_temp_col(sql, ttable, 10, "NULLABLE", MDB_INT, 0, 1); mdb_sql_add_temp_col(sql, ttable, 11, "REMARKS", MDB_TEXT, 254, 0); mdb_sql_add_temp_col(sql, ttable, 12, "COLUMN_DEF", MDB_TEXT, 254, 0); mdb_sql_add_temp_col(sql, ttable, 13, "SQL_DATA_TYPE", MDB_INT, 0, 1); mdb_sql_add_temp_col(sql, ttable, 14, "SQL_DATETIME_SUB", MDB_INT, 0, 1); mdb_sql_add_temp_col(sql, ttable, 15, "CHAR_OCTET_LENGTH", MDB_LONGINT, 0, 1); mdb_sql_add_temp_col(sql, ttable, 16, "ORDINAL_POSITION", MDB_LONGINT, 0, 1); mdb_sql_add_temp_col(sql, ttable, 17, "IS_NULLABLE", MDB_TEXT, 254, 0); mdb_temp_columns_end(ttable); for (i=0; inum_catalog; i++) { entry = g_ptr_array_index(mdb->catalog, i); /* TODO: Do more advanced matching */ if (strcasecmp((char*)szTableName, entry->object_name) != 0) continue; table = mdb_read_table(entry); mdb_read_columns(table); for (j=0; jnum_cols; j++) { col = g_ptr_array_index(table->columns, j); ts2 = mdb_ascii2unicode(mdb, table->name, 0, (char*)t2, MDB_BIND_SIZE); ts3 = mdb_ascii2unicode(mdb, col->name, 0, (char*)t3, MDB_BIND_SIZE); ts5 = mdb_ascii2unicode(mdb, "FIX ME", 0, (char*)t5, MDB_BIND_SIZE); nullable = SQL_NO_NULLS; datatype = _odbc_get_client_type(col); sqldatatype = _odbc_get_client_type(col); ordinal = j+1; /* Set all fields to NULL */ for (k=0; k<18; k++) { FILL_FIELD(&fields[k], NULL, 0); } FILL_FIELD(&fields[2], t2, ts2); FILL_FIELD(&fields[3], t3, ts3); FILL_FIELD(&fields[4], &datatype, 0); FILL_FIELD(&fields[5], t5, ts5); FILL_FIELD(&fields[10], &nullable, 0); FILL_FIELD(&fields[13], &sqldatatype, 0); FILL_FIELD(&fields[16], &ordinal, 0); row_size = mdb_pack_row(ttable, row_buffer, 18, fields); mdb_add_row_to_pg(ttable, row_buffer, row_size); ttable->num_rows++; } mdb_free_tabledef(table); } sql->cur_table = ttable; return SQL_SUCCESS; } SQLRETURN SQL_API SQLColumns( SQLHSTMT hstmt, SQLCHAR *szCatalogName, SQLSMALLINT cbCatalogName, SQLCHAR *szSchemaName, SQLSMALLINT cbSchemaName, SQLCHAR *szTableName, SQLSMALLINT cbTableName, SQLCHAR *szColumnName, SQLSMALLINT cbColumnName) #ifdef HAVE_ATTRIBUTE_ALIAS __attribute__((alias("_SQLColumns"))); #else { return _SQLColumns(hstmt, szCatalogName, cbCatalogName, szSchemaName, cbSchemaName, szTableName, cbTableName, szColumnName, cbColumnName); } #endif #ifdef ENABLE_ODBC_W SQLRETURN SQL_API SQLColumnsW( SQLHSTMT hstmt, SQLWCHAR *szCatalogName, SQLSMALLINT cbCatalogName, SQLWCHAR *szSchemaName, SQLSMALLINT cbSchemaName, SQLWCHAR *szTableName, SQLSMALLINT cbTableName, SQLWCHAR *szColumnName, SQLSMALLINT cbColumnName) { if(cbTableName==SQL_NTS)cbTableName=sqlwlen(szTableName); { SQLCHAR *tmp=calloc(cbTableName*4,1); size_t l=cbTableName*4,z=cbTableName*2; SQLRETURN ret; unicode2ascii((char*)szTableName, &z, (char*)tmp, &l); ret = _SQLColumns(hstmt, NULL, 0, NULL, 0, tmp, l, NULL, 0); free(tmp); return ret; } } #endif //ENABLE_ODBC_W SQLRETURN SQL_API SQLGetConnectOption( SQLHDBC hdbc, SQLUSMALLINT fOption, SQLPOINTER pvParam) { TRACE("SQLGetConnectOption"); return SQL_SUCCESS; } static SQLRETURN SQL_API _SQLGetData( SQLHSTMT hstmt, SQLUSMALLINT icol, SQLSMALLINT fCType, SQLPOINTER rgbValue, SQLLEN cbValueMax, SQLLEN *pcbValue) { struct _hstmt *stmt; struct _hdbc *dbc; struct _henv *env; MdbSQL *sql; MdbHandle *mdb; MdbSQLColumn *sqlcol; MdbColumn *col; MdbTableDef *table; int i, intValue; TRACE("_SQLGetData"); stmt = (struct _hstmt *) hstmt; dbc = (struct _hdbc *) stmt->hdbc; env = (struct _henv *) dbc->henv; sql = env->sql; mdb = sql->mdb; if (icol<1 || icol>sql->num_columns) { strcpy(sqlState, "07009"); return SQL_ERROR; } sqlcol = g_ptr_array_index(sql->columns,icol - 1); table = sql->cur_table; for (i=0;inum_cols;i++) { col=g_ptr_array_index(table->columns,i); if (!strcasecmp(sqlcol->name, col->name)) { break; } } if (i==table->num_cols) return SQL_ERROR; if (icol!=stmt->icol) { stmt->icol=icol; stmt->pos=0; } if (!rgbValue) { strcpy(sqlState, "HY009"); return SQL_ERROR; } if (col->col_type == MDB_BOOL) { // bool cannot be null *(BOOL*)rgbValue = col->cur_value_len ? 0 : 1; if (pcbValue) *pcbValue = 1; return SQL_SUCCESS; } if (col->cur_value_len == 0) { /* When NULL data is retrieved, non-null pcbValue is required */ if (!pcbValue) { strcpy(sqlState, "22002"); return SQL_ERROR; } *pcbValue = SQL_NULL_DATA; return SQL_SUCCESS; } if (fCType==SQL_ARD_TYPE) { // Get _sql_bind_info struct _sql_bind_info *cur; for (cur = stmt->bind_head; cur; cur=cur->next) { if (cur->column_number == icol) { fCType = cur->column_bindtype; goto found_bound_type; } } strcpy(sqlState, "07009"); return SQL_ERROR; } found_bound_type: if (fCType==SQL_C_DEFAULT) fCType = _odbc_get_client_type(col); if (fCType == SQL_C_CHAR) goto to_c_char; switch(col->col_type) { case MDB_BYTE: intValue = (int)mdb_get_byte(mdb->pg_buf, col->cur_value_start); goto to_integer_type; case MDB_INT: intValue = mdb_get_int16(mdb->pg_buf, col->cur_value_start); goto to_integer_type; case MDB_LONGINT: intValue = mdb_get_int32(mdb->pg_buf, col->cur_value_start); goto to_integer_type; to_integer_type: switch (fCType) { case SQL_C_UTINYINT: if (intValue<0 || intValue>UCHAR_MAX) { strcpy(sqlState, "22003"); // Numeric value out of range return SQL_ERROR; } *(SQLCHAR*)rgbValue = (SQLCHAR)intValue; if (pcbValue) *pcbValue = sizeof(SQLCHAR); break; case SQL_C_TINYINT: case SQL_C_STINYINT: if (intValueSCHAR_MAX) { strcpy(sqlState, "22003"); // Numeric value out of range return SQL_ERROR; } *(SQLSCHAR*)rgbValue = (SQLSCHAR)intValue; if (pcbValue) *pcbValue = sizeof(SQLSCHAR); break; case SQL_C_USHORT: case SQL_C_SHORT: if (intValue<0 || intValue>USHRT_MAX) { strcpy(sqlState, "22003"); // Numeric value out of range return SQL_ERROR; } *(SQLSMALLINT*)rgbValue = (SQLSMALLINT)intValue; if (pcbValue) *pcbValue = sizeof(SQLSMALLINT); break; case SQL_C_SSHORT: if (intValueSHRT_MAX) { strcpy(sqlState, "22003"); // Numeric value out of range return SQL_ERROR; } *(SQLSMALLINT*)rgbValue = (SQLSMALLINT)intValue; if (pcbValue) *pcbValue = sizeof(SQLSMALLINT); break; case SQL_C_ULONG: if (intValue<0 || intValue>UINT_MAX) { strcpy(sqlState, "22003"); // Numeric value out of range return SQL_ERROR; } *(SQLUINTEGER*)rgbValue = (SQLINTEGER)intValue; if (pcbValue) *pcbValue = sizeof(SQLINTEGER); break; case SQL_C_LONG: case SQL_C_SLONG: if (intValueLONG_MAX) { strcpy(sqlState, "22003"); // Numeric value out of range return SQL_ERROR; } *(SQLINTEGER*)rgbValue = intValue; if (pcbValue) *pcbValue = sizeof(SQLINTEGER); break; default: strcpy(sqlState, "HYC00"); // Not implemented return SQL_ERROR; } break; // case MDB_MONEY: TODO case MDB_FLOAT: *(float*)rgbValue = mdb_get_single(mdb->pg_buf, col->cur_value_start); if (pcbValue) *pcbValue = sizeof(float); break; case MDB_DOUBLE: *(double*)rgbValue = mdb_get_double(mdb->pg_buf, col->cur_value_start); if (pcbValue) *pcbValue = sizeof(double); break; #if ODBCVER >= 0x0300 // returns text if old odbc case MDB_DATETIME: { struct tm tmp_t; mdb_date_to_tm(mdb_get_double(mdb->pg_buf, col->cur_value_start), &tmp_t); const char *format = mdb_col_get_prop(col, "Format"); if (format && !strcmp(format, "Short Date")) { DATE_STRUCT sql_dt; sql_dt.year = tmp_t.tm_year + 1900; sql_dt.month = tmp_t.tm_mon + 1; sql_dt.day = tmp_t.tm_mday; *(DATE_STRUCT*)rgbValue = sql_dt; if (pcbValue) *pcbValue = sizeof(DATE_STRUCT); } else { TIMESTAMP_STRUCT sql_ts; sql_ts.year = tmp_t.tm_year + 1900; sql_ts.month = tmp_t.tm_mon + 1; sql_ts.day = tmp_t.tm_mday; sql_ts.hour = tmp_t.tm_hour; sql_ts.minute = tmp_t.tm_min; sql_ts.second = tmp_t.tm_sec; sql_ts.fraction = 0; *(TIMESTAMP_STRUCT*)rgbValue = sql_ts; if (pcbValue) *pcbValue = sizeof(TIMESTAMP_STRUCT); } break; } #endif default: /* FIXME here we assume fCType == SQL_C_CHAR */ to_c_char: { char *str = mdb_col_to_string(mdb, mdb->pg_buf, col->cur_value_start, col->col_type, col->cur_value_len); int len = strlen(str) + 1; // including \0 if (stmt->pos >= len) { free(str); return SQL_NO_DATA; } if (!cbValueMax) { if (pcbValue) *pcbValue = len; free(str); return SQL_SUCCESS_WITH_INFO; } if (len - stmt->pos > cbValueMax) { /* the buffer we were given is too small, so truncate it to the size of the buffer */ strncpy(rgbValue, str, cbValueMax); if (pcbValue) *pcbValue = cbValueMax; stmt->pos += cbValueMax; free(str); strcpy(sqlState, "01004"); // trunctated return SQL_SUCCESS_WITH_INFO; } strncpy(rgbValue, str + stmt->pos, len - stmt->pos); if (pcbValue) *pcbValue = len - stmt->pos; stmt->pos += len - stmt->pos; free(str); break; } } return SQL_SUCCESS; } SQLRETURN SQL_API SQLGetData( SQLHSTMT hstmt, SQLUSMALLINT icol, SQLSMALLINT fCType, SQLPOINTER rgbValue, SQLLEN cbValueMax, SQLLEN *pcbValue) #ifdef HAVE_ATTRIBUTE_ALIAS __attribute__((alias("_SQLGetData"))); #else { return _SQLGetData(hstmt, icol, fCType, rgbValue, cbValueMax, pcbValue); } #endif #ifdef ENABLE_ODBC_W SQLRETURN SQL_API SQLGetDataW( SQLHSTMT hstmt, SQLUSMALLINT icol, SQLSMALLINT fCType, SQLPOINTER rgbValue, SQLLEN cbValueMax, SQLLEN *pcbValue) { //todo: treat numbers correctly SQLCHAR *tmp=calloc(cbValueMax*4,1); size_t l=cbValueMax*4; SQLRETURN ret = _SQLGetData(hstmt, icol, fCType, tmp, cbValueMax*4, (SQLLEN*)&l); ascii2unicode((char*)tmp, &l, (char*)rgbValue, (size_t*)pcbValue); *pcbValue/=sizeof(SQLWCHAR); free(tmp); return ret; } #endif //ENABLE_ODBC_W static void _set_func_exists(SQLUSMALLINT *pfExists, SQLUSMALLINT fFunction) { SQLUSMALLINT *mod; mod = pfExists + (fFunction >> 4); *mod |= (1 << (fFunction & 0x0f)); } SQLRETURN SQL_API SQLGetFunctions( SQLHDBC hdbc, SQLUSMALLINT fFunction, SQLUSMALLINT *pfExists) { TRACE("SQLGetFunctions"); switch (fFunction) { #if ODBCVER >= 0x0300 case SQL_API_ODBC3_ALL_FUNCTIONS: bzero(pfExists, SQL_API_ODBC3_ALL_FUNCTIONS_SIZE); _set_func_exists(pfExists,SQL_API_SQLALLOCCONNECT); _set_func_exists(pfExists,SQL_API_SQLALLOCENV); _set_func_exists(pfExists,SQL_API_SQLALLOCHANDLE); _set_func_exists(pfExists,SQL_API_SQLALLOCSTMT); _set_func_exists(pfExists,SQL_API_SQLBINDCOL); _set_func_exists(pfExists,SQL_API_SQLBINDPARAMETER); _set_func_exists(pfExists,SQL_API_SQLCANCEL); //_set_func_exists(pfExists,SQL_API_SQLCLOSECURSOR); _set_func_exists(pfExists,SQL_API_SQLCOLATTRIBUTE); _set_func_exists(pfExists,SQL_API_SQLCOLUMNS); _set_func_exists(pfExists,SQL_API_SQLCONNECT); //_set_func_exists(pfExists,SQL_API_SQLCOPYDESC); _set_func_exists(pfExists,SQL_API_SQLDATASOURCES); _set_func_exists(pfExists,SQL_API_SQLDESCRIBECOL); _set_func_exists(pfExists,SQL_API_SQLDISCONNECT); //_set_func_exists(pfExists,SQL_API_SQLENDTRAN); _set_func_exists(pfExists,SQL_API_SQLERROR); _set_func_exists(pfExists,SQL_API_SQLEXECDIRECT); _set_func_exists(pfExists,SQL_API_SQLEXECUTE); _set_func_exists(pfExists,SQL_API_SQLFETCH); //_set_func_exists(pfExists,SQL_API_SQLFETCHSCROLL); _set_func_exists(pfExists,SQL_API_SQLFREECONNECT); _set_func_exists(pfExists,SQL_API_SQLFREEENV); _set_func_exists(pfExists,SQL_API_SQLFREEHANDLE); _set_func_exists(pfExists,SQL_API_SQLFREESTMT); //_set_func_exists(pfExists,SQL_API_SQLGETCONNECTATTR); _set_func_exists(pfExists,SQL_API_SQLGETCONNECTOPTION); _set_func_exists(pfExists,SQL_API_SQLGETCURSORNAME); _set_func_exists(pfExists,SQL_API_SQLGETDATA); //_set_func_exists(pfExists,SQL_API_SQLGETDESCFIELD); //_set_func_exists(pfExists,SQL_API_SQLGETDESCREC); //_set_func_exists(pfExists,SQL_API_SQLGETDIAGFIELD); //_set_func_exists(pfExists,SQL_API_SQLGETDIAGREC); //_set_func_exists(pfExists,SQL_API_SQLGETENVATTR); _set_func_exists(pfExists,SQL_API_SQLGETFUNCTIONS); _set_func_exists(pfExists,SQL_API_SQLGETINFO); _set_func_exists(pfExists,SQL_API_SQLGETSTMTATTR); _set_func_exists(pfExists,SQL_API_SQLGETSTMTOPTION); _set_func_exists(pfExists,SQL_API_SQLGETTYPEINFO); _set_func_exists(pfExists,SQL_API_SQLNUMRESULTCOLS); _set_func_exists(pfExists,SQL_API_SQLPARAMDATA); _set_func_exists(pfExists,SQL_API_SQLPREPARE); _set_func_exists(pfExists,SQL_API_SQLPUTDATA); _set_func_exists(pfExists,SQL_API_SQLROWCOUNT); //_set_func_exists(pfExists,SQL_API_SQLSETCONNECTATTR); _set_func_exists(pfExists,SQL_API_SQLSETCONNECTOPTION); _set_func_exists(pfExists,SQL_API_SQLSETCURSORNAME); //_set_func_exists(pfExists,SQL_API_SQLSETDESCFIELD); //_set_func_exists(pfExists,SQL_API_SQLSETDESCREC); _set_func_exists(pfExists,SQL_API_SQLSETENVATTR); _set_func_exists(pfExists,SQL_API_SQLSETPARAM); //_set_func_exists(pfExists,SQL_API_SQLSETSTMTATTR); _set_func_exists(pfExists,SQL_API_SQLSETSTMTOPTION); _set_func_exists(pfExists,SQL_API_SQLSPECIALCOLUMNS); _set_func_exists(pfExists,SQL_API_SQLSTATISTICS); _set_func_exists(pfExists,SQL_API_SQLTABLES); _set_func_exists(pfExists,SQL_API_SQLTRANSACT); break; #endif case SQL_API_ALL_FUNCTIONS: bzero(pfExists, 100); // 100 by spec _set_func_exists(pfExists,SQL_API_SQLALLOCCONNECT); _set_func_exists(pfExists,SQL_API_SQLALLOCENV); _set_func_exists(pfExists,SQL_API_SQLALLOCSTMT); _set_func_exists(pfExists,SQL_API_SQLBINDCOL); _set_func_exists(pfExists,SQL_API_SQLCANCEL); _set_func_exists(pfExists,SQL_API_SQLCOLATTRIBUTE); _set_func_exists(pfExists,SQL_API_SQLCOLUMNS); _set_func_exists(pfExists,SQL_API_SQLCONNECT); _set_func_exists(pfExists,SQL_API_SQLDATASOURCES); _set_func_exists(pfExists,SQL_API_SQLDESCRIBECOL); _set_func_exists(pfExists,SQL_API_SQLDISCONNECT); _set_func_exists(pfExists,SQL_API_SQLERROR); _set_func_exists(pfExists,SQL_API_SQLEXECDIRECT); _set_func_exists(pfExists,SQL_API_SQLEXECUTE); _set_func_exists(pfExists,SQL_API_SQLFETCH); _set_func_exists(pfExists,SQL_API_SQLFREECONNECT); _set_func_exists(pfExists,SQL_API_SQLFREEENV); _set_func_exists(pfExists,SQL_API_SQLFREEHANDLE); _set_func_exists(pfExists,SQL_API_SQLFREESTMT); _set_func_exists(pfExists,SQL_API_SQLGETCONNECTOPTION); _set_func_exists(pfExists,SQL_API_SQLGETCURSORNAME); _set_func_exists(pfExists,SQL_API_SQLGETDATA); _set_func_exists(pfExists,SQL_API_SQLGETFUNCTIONS); _set_func_exists(pfExists,SQL_API_SQLGETINFO); _set_func_exists(pfExists,SQL_API_SQLGETSTMTATTR); _set_func_exists(pfExists,SQL_API_SQLGETSTMTOPTION); _set_func_exists(pfExists,SQL_API_SQLGETTYPEINFO); _set_func_exists(pfExists,SQL_API_SQLNUMRESULTCOLS); _set_func_exists(pfExists,SQL_API_SQLPARAMDATA); _set_func_exists(pfExists,SQL_API_SQLPREPARE); _set_func_exists(pfExists,SQL_API_SQLPUTDATA); _set_func_exists(pfExists,SQL_API_SQLROWCOUNT); _set_func_exists(pfExists,SQL_API_SQLSETCONNECTOPTION); _set_func_exists(pfExists,SQL_API_SQLSETCURSORNAME); _set_func_exists(pfExists,SQL_API_SQLSETENVATTR); _set_func_exists(pfExists,SQL_API_SQLSETPARAM); _set_func_exists(pfExists,SQL_API_SQLSETSTMTOPTION); _set_func_exists(pfExists,SQL_API_SQLSPECIALCOLUMNS); _set_func_exists(pfExists,SQL_API_SQLSTATISTICS); _set_func_exists(pfExists,SQL_API_SQLTABLES); _set_func_exists(pfExists,SQL_API_SQLTRANSACT); break; case SQL_API_SQLALLOCCONNECT: case SQL_API_SQLALLOCENV: case SQL_API_SQLALLOCSTMT: case SQL_API_SQLBINDCOL: case SQL_API_SQLCANCEL: case SQL_API_SQLCOLATTRIBUTE: case SQL_API_SQLCOLUMNS: case SQL_API_SQLCONNECT: case SQL_API_SQLDATASOURCES: case SQL_API_SQLDESCRIBECOL: case SQL_API_SQLDISCONNECT: case SQL_API_SQLERROR: case SQL_API_SQLEXECDIRECT: case SQL_API_SQLEXECUTE: case SQL_API_SQLFETCH: case SQL_API_SQLFREECONNECT: case SQL_API_SQLFREEENV: case SQL_API_SQLFREEHANDLE: case SQL_API_SQLFREESTMT: case SQL_API_SQLGETCONNECTOPTION: case SQL_API_SQLGETCURSORNAME: case SQL_API_SQLGETDATA: case SQL_API_SQLGETFUNCTIONS: case SQL_API_SQLGETINFO: case SQL_API_SQLGETSTMTATTR: case SQL_API_SQLGETSTMTOPTION: case SQL_API_SQLGETTYPEINFO: case SQL_API_SQLNUMRESULTCOLS: case SQL_API_SQLPARAMDATA: case SQL_API_SQLPREPARE: case SQL_API_SQLPUTDATA: case SQL_API_SQLROWCOUNT: case SQL_API_SQLSETCONNECTOPTION: case SQL_API_SQLSETCURSORNAME: case SQL_API_SQLSETENVATTR: case SQL_API_SQLSETPARAM: case SQL_API_SQLSETSTMTOPTION: case SQL_API_SQLSPECIALCOLUMNS: case SQL_API_SQLSTATISTICS: case SQL_API_SQLTABLES: case SQL_API_SQLTRANSACT: *pfExists = 1; /* SQL_TRUE */ break; default: *pfExists = 0; /* SQL_FALSE */ break; } return SQL_SUCCESS; } static SQLRETURN SQL_API _SQLGetInfo( SQLHDBC hdbc, SQLUSMALLINT fInfoType, SQLPOINTER rgbInfoValue, SQLSMALLINT cbInfoValueMax, SQLSMALLINT *pcbInfoValue) { TRACE("_SQLGetInfo"); switch (fInfoType) { case SQL_MAX_STATEMENT_LEN: if (rgbInfoValue) *((SQLUINTEGER *)rgbInfoValue) = (SQLUINTEGER)65000; if (pcbInfoValue) *pcbInfoValue = sizeof(SQLUINTEGER); break; case SQL_SCHEMA_USAGE: if (rgbInfoValue) *((SQLSMALLINT *)rgbInfoValue) = (SQLSMALLINT)0; if (pcbInfoValue) *pcbInfoValue = sizeof(SQLSMALLINT); break; case SQL_CATALOG_NAME_SEPARATOR: if (rgbInfoValue) memcpy(rgbInfoValue, ".", 1); if (pcbInfoValue) *pcbInfoValue = 1; break; case SQL_CATALOG_LOCATION: if (rgbInfoValue) *((SQLSMALLINT *)rgbInfoValue) = (SQLSMALLINT)1; if (pcbInfoValue) *pcbInfoValue = sizeof(SQLSMALLINT); break; case SQL_IDENTIFIER_QUOTE_CHAR: if (rgbInfoValue) memcpy(rgbInfoValue, "\"", 1); if (pcbInfoValue) *pcbInfoValue = 1; break; case SQL_DBMS_NAME: if (rgbInfoValue) strncpy(rgbInfoValue, "MDBTOOLS", cbInfoValueMax); if (pcbInfoValue) *pcbInfoValue = 9; break; case SQL_DBMS_VER: if (rgbInfoValue) strncpy(rgbInfoValue, VERSION, cbInfoValueMax); if (pcbInfoValue) *pcbInfoValue = sizeof(VERSION)+1; break; default: if (pcbInfoValue) *pcbInfoValue = 0; strcpy(sqlState, "HYC00"); return SQL_ERROR; } return SQL_SUCCESS; } SQLRETURN SQL_API SQLGetInfo( SQLHDBC hdbc, SQLUSMALLINT fInfoType, SQLPOINTER rgbInfoValue, SQLSMALLINT cbInfoValueMax, SQLSMALLINT *pcbInfoValue) #ifdef HAVE_ATTRIBUTE_ALIAS __attribute__((alias("_SQLGetInfo"))); #else { return _SQLGetInfo(hdbc, fInfoType, rgbInfoValue, cbInfoValueMax, pcbInfoValue); } #endif #ifdef ENABLE_ODBC_W SQLRETURN SQL_API SQLGetInfoW( SQLHDBC hdbc, SQLUSMALLINT fInfoType, SQLPOINTER rgbInfoValue, SQLSMALLINT cbInfoValueMax, SQLSMALLINT *pcbInfoValue) { TRACE("SQLGetInfoW"); if(fInfoType==SQL_MAX_STATEMENT_LEN||fInfoType==SQL_SCHEMA_USAGE||fInfoType==SQL_CATALOG_LOCATION) return _SQLGetInfo(hdbc,fInfoType,rgbInfoValue,cbInfoValueMax,pcbInfoValue); SQLCHAR *tmp=calloc(cbInfoValueMax*4,1); size_t l=cbInfoValueMax*4; SQLRETURN ret = _SQLGetInfo(hdbc, fInfoType, tmp, cbInfoValueMax*4,(SQLSMALLINT*)&l); size_t pcb=cbInfoValueMax; ascii2unicode((char*)tmp, &l, (char*)rgbInfoValue, &pcb); pcb/=sizeof(SQLWCHAR); if(pcbInfoValue)*pcbInfoValue=pcb; free(tmp); return ret; } #endif //ENABLE_ODBC_W SQLRETURN SQL_API SQLGetStmtOption( SQLHSTMT hstmt, SQLUSMALLINT fOption, SQLPOINTER pvParam) { TRACE("SQLGetStmtOption"); return SQL_SUCCESS; } SQLRETURN SQL_API SQLGetTypeInfo( SQLHSTMT hstmt, SQLSMALLINT fSqlType) { struct _hstmt *stmt = (struct _hstmt *) hstmt; struct _hdbc *dbc = (struct _hdbc *) stmt->hdbc; struct _henv *env = (struct _henv *) dbc->henv; MdbTableDef *ttable; MdbSQL *sql = env->sql; MdbHandle *mdb = sql->mdb; int row_size; unsigned char row_buffer[MDB_PGSIZE]; unsigned int ts0, ts3, ts4, ts5, ts12; unsigned char t0[MDB_BIND_SIZE], t3[MDB_BIND_SIZE], t4[MDB_BIND_SIZE], t5[MDB_BIND_SIZE], t12[MDB_BIND_SIZE]; int i; MdbField fields[NUM_TYPE_INFO_COLS]; TRACE("SQLGetTypeInfo"); ttable = mdb_create_temp_table(mdb, "#typeinfo"); mdb_sql_add_temp_col(sql, ttable, 0, "TYPE_NAME", MDB_TEXT, 30, 0); mdb_sql_add_temp_col(sql, ttable, 1, "DATA_TYPE", MDB_INT, 0, 1); mdb_sql_add_temp_col(sql, ttable, 2, "COLUMN_SIZE", MDB_LONGINT, 0, 1); mdb_sql_add_temp_col(sql, ttable, 3, "LITERAL_PREFIX", MDB_TEXT, 30, 0); mdb_sql_add_temp_col(sql, ttable, 4, "LITERAL_SUFFIX", MDB_TEXT, 30, 0); mdb_sql_add_temp_col(sql, ttable, 5, "CREATE_PARAMS", MDB_TEXT, 30, 0); mdb_sql_add_temp_col(sql, ttable, 6, "NULLABLE", MDB_INT, 0, 1); mdb_sql_add_temp_col(sql, ttable, 7, "CASE_SENSITIVE", MDB_INT, 0, 1); mdb_sql_add_temp_col(sql, ttable, 8, "SEARCHABLE", MDB_INT, 0, 1); mdb_sql_add_temp_col(sql, ttable, 9, "UNSIGNED_ATTRIBUTE", MDB_INT, 0, 1); mdb_sql_add_temp_col(sql, ttable, 10, "FIXED_PREC_SCALE", MDB_INT, 0, 1); mdb_sql_add_temp_col(sql, ttable, 11, "AUTO_UNIQUE_VALUE", MDB_INT, 0, 1); mdb_sql_add_temp_col(sql, ttable, 12, "LOCAL_TYPE_NAME", MDB_TEXT, 30, 0); mdb_sql_add_temp_col(sql, ttable, 13, "MINIMUM_SCALE", MDB_INT, 0, 1); mdb_sql_add_temp_col(sql, ttable, 14, "MAXIMUM_SCALE", MDB_INT, 0, 1); mdb_sql_add_temp_col(sql, ttable, 15, "SQL_DATA_TYPE", MDB_INT, 0, 1); mdb_sql_add_temp_col(sql, ttable, 16, "SQL_DATETIME_SUB", MDB_INT, 0, 1); mdb_sql_add_temp_col(sql, ttable, 17, "NUM_PREC_RADIX", MDB_INT, 0, 1); mdb_sql_add_temp_col(sql, ttable, 18, "INTERVAL_PRECISION", MDB_INT, 0, 1); mdb_temp_columns_end(ttable); for (i=0; inum_rows++; } sql->cur_table = ttable; /* return _SQLExecute(hstmt); */ return SQL_SUCCESS; } SQLRETURN SQL_API SQLParamData( SQLHSTMT hstmt, SQLPOINTER *prgbValue) { TRACE("SQLParamData"); return SQL_SUCCESS; } SQLRETURN SQL_API SQLPutData( SQLHSTMT hstmt, SQLPOINTER rgbValue, SQLLEN cbValue) { TRACE("SQLPutData"); return SQL_SUCCESS; } SQLRETURN SQL_API SQLSetConnectOption( SQLHDBC hdbc, SQLUSMALLINT fOption, SQLULEN vParam) { TRACE("SQLSetConnectOption"); return SQL_SUCCESS; } SQLRETURN SQL_API SQLSetStmtOption( SQLHSTMT hstmt, SQLUSMALLINT fOption, SQLULEN vParam) { TRACE("SQLSetStmtOption"); return SQL_SUCCESS; } SQLRETURN SQL_API SQLSpecialColumns( SQLHSTMT hstmt, SQLUSMALLINT fColType, SQLCHAR *szCatalogName, SQLSMALLINT cbCatalogName, SQLCHAR *szSchemaName, SQLSMALLINT cbSchemaName, SQLCHAR *szTableName, SQLSMALLINT cbTableName, SQLUSMALLINT fScope, SQLUSMALLINT fNullable) { TRACE("SQLSpecialColumns"); return SQL_SUCCESS; } SQLRETURN SQL_API SQLStatistics( SQLHSTMT hstmt, SQLCHAR *szCatalogName, SQLSMALLINT cbCatalogName, SQLCHAR *szSchemaName, SQLSMALLINT cbSchemaName, SQLCHAR *szTableName, SQLSMALLINT cbTableName, SQLUSMALLINT fUnique, SQLUSMALLINT fAccuracy) { TRACE("SQLStatistics"); return SQL_SUCCESS; } SQLRETURN SQL_API SQLTables( //sz* not used, so Unicode API not required. SQLHSTMT hstmt, SQLCHAR *szCatalogName, SQLSMALLINT cbCatalogName, SQLCHAR *szSchemaName, SQLSMALLINT cbSchemaName, SQLCHAR *szTableName, SQLSMALLINT cbTableName, SQLCHAR *szTableType, SQLSMALLINT cbTableType) { struct _hstmt *stmt = (struct _hstmt *) hstmt; struct _hdbc *dbc = (struct _hdbc *) stmt->hdbc; struct _henv *env = (struct _henv *) dbc->henv; MdbSQL *sql = env->sql; MdbHandle *mdb = sql->mdb; MdbTableDef *ttable; MdbField fields[5]; MdbCatalogEntry *entry; unsigned char row_buffer[MDB_PGSIZE]; char *table_types[] = {"TABLE", "SYSTEM TABLE", "VIEW"}; unsigned int i, j, row_size, ttype; unsigned int ts2, ts3; unsigned char t2[MDB_BIND_SIZE], t3[MDB_BIND_SIZE]; TRACE("SQLTables"); mdb_read_catalog(mdb, MDB_ANY); ttable = mdb_create_temp_table(mdb, "#tables"); mdb_sql_add_temp_col(sql, ttable, 0, "TABLE_CAT", MDB_TEXT, 128, 0); mdb_sql_add_temp_col(sql, ttable, 1, "TABLE_SCHEM", MDB_TEXT, 128, 0); mdb_sql_add_temp_col(sql, ttable, 2, "TABLE_NAME", MDB_TEXT, 128, 0); mdb_sql_add_temp_col(sql, ttable, 3, "TABLE_TYPE", MDB_TEXT, 128, 0); mdb_sql_add_temp_col(sql, ttable, 4, "REMARKS", MDB_TEXT, 254, 0); mdb_temp_columns_end(ttable); /* TODO: Sort the return list by TYPE, CAT, SCHEM, NAME */ for (i=0; inum_catalog; i++) { entry = g_ptr_array_index(mdb->catalog, i); if (mdb_is_user_table(entry)) ttype = 0; else if (mdb_is_system_table(entry)) ttype = 1; else if (entry->object_type == MDB_QUERY) ttype = 2; else continue; /* Set all fields to NULL */ for (j=0; j<5; j++) { FILL_FIELD(&fields[j], NULL, 0); } ts2 = mdb_ascii2unicode(mdb, entry->object_name, 0, (char*)t2, MDB_BIND_SIZE); ts3 = mdb_ascii2unicode(mdb, table_types[ttype], 0, (char*)t3, MDB_BIND_SIZE); FILL_FIELD(&fields[2], t2, ts2); FILL_FIELD(&fields[3], t3, ts3); row_size = mdb_pack_row(ttable, row_buffer, 5, fields); mdb_add_row_to_pg(ttable, row_buffer, row_size); ttable->num_rows++; } sql->cur_table = ttable; return SQL_SUCCESS; } SQLRETURN SQL_API SQLDataSources( SQLHENV henv, SQLUSMALLINT fDirection, SQLCHAR *szDSN, SQLSMALLINT cbDSNMax, SQLSMALLINT *pcbDSN, SQLCHAR *szDescription, SQLSMALLINT cbDescriptionMax, SQLSMALLINT *pcbDescription) { TRACE("SQLDataSources"); return SQL_SUCCESS; } static int _odbc_fix_literals(struct _hstmt *stmt) { char tmp[4096],begin_tag[11]; char *s, *d, *p; int i, quoted = 0, find_end = 0; char quote_char; s=stmt->query; d=tmp; while (*s) { if (!quoted && (*s=='"' || *s=='\'')) { quoted = 1; quote_char = *s; } else if (quoted && *s==quote_char) { quoted = 0; } if (!quoted && find_end && *s=='}') { s++; /* ignore the end of tag */ } else if (!quoted && *s=='{') { for (p=s,i=0;*p && *p!=' ';p++) i++; if (i>10) { /* garbage */ *d++=*s++; } else { strncpy(begin_tag, s, i); begin_tag[i] = '\0'; /* printf("begin tag %s\n", begin_tag); */ s += i; find_end = 1; } } else { *d++=*s++; } } *d='\0'; strcpy(stmt->query,tmp); return 0; } static int _odbc_get_string_size(int size, SQLCHAR *str) { if (!str) { return 0; } if (size==SQL_NTS) { return strlen((char*)str); } else { return size; } return 0; } /* static int _odbc_get_server_type(int clt_type) { switch (clt_type) { case SQL_CHAR: case SQL_VARCHAR: case SQL_BIT: case SQL_TINYINT: case SQL_SMALLINT: case SQL_INTEGER: case SQL_DOUBLE: case SQL_DECIMAL: case SQL_NUMERIC: case SQL_FLOAT: default: break; } return 0; }*/ static SQLSMALLINT _odbc_get_client_type(MdbColumn *col) { switch (col->col_type) { case MDB_BOOL: return SQL_BIT; case MDB_BYTE: return SQL_TINYINT; case MDB_INT: return SQL_SMALLINT; case MDB_LONGINT: return SQL_INTEGER; case MDB_MONEY: return SQL_DECIMAL; case MDB_FLOAT: return SQL_FLOAT; case MDB_DOUBLE: return SQL_DOUBLE; case MDB_DATETIME: ; #if ODBCVER >= 0x0300 const char *format = mdb_col_get_prop(col, "Format"); if (format && !strcmp(format, "Short Date")) return SQL_TYPE_DATE; else return SQL_TYPE_TIMESTAMP; #endif // returns text otherwise case MDB_TEXT: return SQL_VARCHAR; default: // fprintf(stderr,"Unknown type %d\n",srv_type); break; } return -1; } mdbtools-0.7.1/src/odbc/unittest.c000066400000000000000000000123341222645741400170750ustar00rootroot00000000000000/* FreeTDS - Library of routines accessing Sybase and Microsoft databases * Copyright (C) 1998-1999 Brian Bruns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* #include */ #include #include #include #define SALES_PERSON_LEN 2 #define STATUS_LEN 6 SQLSMALLINT sOrderID; SQLSMALLINT sCustID; DATE_STRUCT dsOpenDate; SQLCHAR szSalesPerson[SALES_PERSON_LEN] = "D"; SQLCHAR szStatus[STATUS_LEN]; SQLINTEGER cbOrderID = 0, cbCustID = 0, cbOpenDate = 0, cbSalesPerson = SQL_NTS, cbStatus = SQL_NTS; SQLRETURN retcode; HENV henv; HDBC hdbc; SQLHSTMT hstmt; static void printStatementError(HSTMT hstmt, char *msg) { UCHAR szSqlState[6]; UCHAR szErrorMsg[SQL_MAX_MESSAGE_LENGTH]; SQLINTEGER dwNativeError; SWORD wErrorMsg; SQLError(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt, szSqlState, &dwNativeError, szErrorMsg, SQL_MAX_MESSAGE_LENGTH-1, &wErrorMsg); fprintf(stderr,"%s\n%s\n%s\n",msg, szSqlState, szErrorMsg); } int main() { int i; retcode = SQLAllocEnv(&henv); if (SQLAllocConnect(henv, &hdbc) != SQL_SUCCESS) { UCHAR szSqlState[6]; UCHAR szErrorMsg[SQL_MAX_MESSAGE_LENGTH]; SQLINTEGER dwNativeError; SWORD wErrorMsg; SQLError(henv, SQL_NULL_HDBC, SQL_NULL_HSTMT, szSqlState, &dwNativeError, szErrorMsg, SQL_MAX_MESSAGE_LENGTH-1, &wErrorMsg); fprintf(stderr,"problem with SQLAllocConnect\n%s\n%s\n", szSqlState, szErrorMsg); return 1; } retcode = SQLSetConnectOption(hdbc, SQL_ACCESS_MODE, SQL_MODE_READ_ONLY); if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) { UCHAR szSqlState[6]; UCHAR szErrorMsg[SQL_MAX_MESSAGE_LENGTH]; SQLINTEGER dwNativeError; SWORD wErrorMsg; SQLError(SQL_NULL_HENV, hdbc, SQL_NULL_HSTMT, szSqlState, &dwNativeError, szErrorMsg, SQL_MAX_MESSAGE_LENGTH-1, &wErrorMsg); fprintf(stderr,"problem with SQLSetConnectOption\n%s\n%s\n", szSqlState, szErrorMsg); return 1; } retcode = SQLSetConnectOption(hdbc, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_ON); if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) { UCHAR szSqlState[6]; UCHAR szErrorMsg[SQL_MAX_MESSAGE_LENGTH]; SQLINTEGER dwNativeError; SWORD wErrorMsg; SQLError(SQL_NULL_HENV, hdbc, SQL_NULL_HSTMT, szSqlState, &dwNativeError, szErrorMsg, SQL_MAX_MESSAGE_LENGTH-1, &wErrorMsg); fprintf(stderr,"problem with SQLSetConnectOption\n%s\n%s\n", szSqlState, szErrorMsg); return 1; } retcode = SQLConnect(hdbc, (UCHAR *)"Northwind", SQL_NTS, (UCHAR *)"", SQL_NTS, (UCHAR *)"", SQL_NTS); if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) { UCHAR szSqlState[6]; UCHAR szErrorMsg[SQL_MAX_MESSAGE_LENGTH]; SQLINTEGER dwNativeError; SWORD wErrorMsg; SQLError(SQL_NULL_HENV, hdbc, SQL_NULL_HSTMT, szSqlState, &dwNativeError, szErrorMsg, SQL_MAX_MESSAGE_LENGTH-1, &wErrorMsg); fprintf(stderr,"problem with SQLConnect\n%s\n%s\n", szSqlState, szErrorMsg); return 1; } if (SQLAllocStmt(hdbc, &hstmt)!= SQL_SUCCESS) { UCHAR szSqlState[6]; UCHAR szErrorMsg[SQL_MAX_MESSAGE_LENGTH]; SQLINTEGER dwNativeError; SWORD wErrorMsg; SQLError(SQL_NULL_HENV, hdbc, SQL_NULL_HSTMT, szSqlState, &dwNativeError, szErrorMsg, SQL_MAX_MESSAGE_LENGTH-1, &wErrorMsg); fprintf(stderr,"problem with SQLAllocStmt\n%s\n%s\n", szSqlState, szErrorMsg); return 1; } /* Prepare the SQL statement with parameter markers. */ retcode = SQLPrepare(hstmt, (unsigned char *)"select * from Shippers", SQL_NTS); if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { UCHAR szCol1[60]; SQLLEN length; printf("excecuting first statement\n"); retcode = SQLExecute(hstmt); if (retcode != SQL_SUCCESS) { UCHAR szSqlState[6]; UCHAR szErrorMsg[SQL_MAX_MESSAGE_LENGTH]; SQLINTEGER dwNativeError; SWORD wErrorMsg; SQLError(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt, szSqlState, &dwNativeError, szErrorMsg, SQL_MAX_MESSAGE_LENGTH-1, &wErrorMsg); fprintf(stderr,"problem with SQLExecute\n%s\n%s\n", szSqlState, szErrorMsg); return 1; } SQLBindCol(hstmt, 3, SQL_CHAR, szCol1, 60, &length); //SQLBindCol(hstmt, 1, SQL_CHAR, szCol1, 60, NULL); /* Execute statement with first row. */ i=0; while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS) { i++; printf("%d: szCol1 = %s (%d)\n", i, szCol1, (int)length); } if (retcode != SQL_NO_DATA_FOUND) { printStatementError(hstmt, "problem with SQLFetch"); return 1; } } printf("Done\n"); return 1; } mdbtools-0.7.1/src/sql/000077500000000000000000000000001222645741400147375ustar00rootroot00000000000000mdbtools-0.7.1/src/sql/Makefile.am000066400000000000000000000005061222645741400167740ustar00rootroot00000000000000lib_LTLIBRARIES = libmdbsql.la libmdbsql_la_SOURCES= mdbsql.c parser.y lexer.l libmdbsql_la_LDFLAGS = -version-info 2:0:0 -export-symbols-regex '^mdb_sql_' CLEANFILES = parser.c parser.h lexer.c AM_CFLAGS = -I$(top_srcdir)/include $(GLIB_CFLAGS) LIBS = $(GLIB_LIBS) libmdbsql_la_LIBADD = ../libmdb/libmdb.la YACC = @YACC@ -d mdbtools-0.7.1/src/sql/lexer.l000066400000000000000000000050441222645741400162360ustar00rootroot00000000000000%{ /* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "mdbsql.h" #include "parser.h" extern int mdb_sql_yyinput(char *buf, int need); %} %option nounput %option noinput %% select { return SELECT; } from { return FROM; } connect { return CONNECT; } disconnect { return DISCONNECT; } to { return TO; } list { return LIST; } where { return WHERE; } tables { return TABLES; } table { return TABLE; } describe { return DESCRIBE; } and { return AND; } or { return OR; } not { return NOT; } is { return IS; } null { return NUL; } (<=) { return LTEQ; } (>=) { return GTEQ; } like { return LIKE; } [ \t\r] ; \"[^"]*\"\" { yyless(yyleng-1); yymore(); } \"[^"]*\" { int ip, op, ilen; ilen = strlen(yytext); yylval.name = malloc(ilen-1); for (ip=1, op=0; ip #include "mdbsql.h" #ifdef DMALLOC #include "dmalloc.h" #endif #ifdef HAVE_WORDEXP_H #define HAVE_WORDEXP #include #endif char *g_input_ptr; /* Prevent warnings from -Wmissing-prototypes. */ #ifdef YYPARSE_PARAM #if defined __STDC__ || defined __cplusplus int yyparse (void *YYPARSE_PARAM); #else int yyparse (); #endif #else /* ! YYPARSE_PARAM */ #if defined __STDC__ || defined __cplusplus int yyparse (void); #else int yyparse (); #endif #endif /* ! YYPARSE_PARAM */ void mdb_sql_error(MdbSQL* sql, char *fmt, ...) { va_list ap; va_start(ap, fmt); vsnprintf(sql->error_msg, sizeof(sql->error_msg), fmt, ap); va_end(ap); fprintf(stderr, "%s\n", sql->error_msg); } int mdb_sql_yyinput(char *buf, int need) { int cplen, have; have = strlen(g_input_ptr); cplen = need > have ? have : need; if (cplen>0) { memcpy(buf, g_input_ptr, cplen); g_input_ptr += cplen; } return cplen; } MdbSQL *mdb_sql_init() { MdbSQL *sql; sql = (MdbSQL *) g_malloc0(sizeof(MdbSQL)); sql->columns = g_ptr_array_new(); sql->tables = g_ptr_array_new(); sql->sarg_tree = NULL; sql->sarg_stack = NULL; sql->max_rows = -1; return sql; } #ifndef _ #define _(x) x #endif /** * mdb_sql_run_query: * @sql: MDB SQL object to execute the query on. * @querystr: SQL query string to execute. * * Parses @querystr and executes it within the given @sql object. * * Returns: the updated MDB SQL object, or NULL on error **/ MdbSQL* mdb_sql_run_query (MdbSQL* sql, const gchar* querystr) { g_return_val_if_fail (sql, NULL); g_return_val_if_fail (querystr, NULL); g_input_ptr = (gchar*) querystr; /* calls to yyparse should be serialized for thread safety */ /* begin unsafe */ _mdb_sql (sql); sql->error_msg[0]='\0'; if (yyparse()) { /* end unsafe */ mdb_sql_error (sql, _("Could not parse '%s' command"), querystr); mdb_sql_reset (sql); return NULL; } if (sql->cur_table == NULL) { /* Invalid column name? (should get caught by mdb_sql_select, * but it appeared to happen anyway with 0.5) */ mdb_sql_error (sql, _("Got no result for '%s' command"), querystr); return NULL; } mdb_sql_bind_all (sql); return sql; } void mdb_sql_set_maxrow(MdbSQL *sql, int maxrow) { sql->max_rows = maxrow; } static void mdb_sql_free_columns(GPtrArray *columns) { unsigned int i; if (!columns) return; for (i=0; ilen; i++) { MdbSQLColumn *c = (MdbSQLColumn *)g_ptr_array_index(columns, i); g_free(c->name); g_free(c); } g_ptr_array_free(columns, TRUE); } static void mdb_sql_free_tables(GPtrArray *tables) { unsigned int i; if (!tables) return; for (i=0; ilen; i++) { MdbSQLTable *t = (MdbSQLTable *)g_ptr_array_index(tables, i); g_free(t->name); g_free(t); } g_ptr_array_free(tables, TRUE); } void mdb_sql_close(MdbSQL *sql) { if (sql->mdb) { mdb_close(sql->mdb); sql->mdb = NULL; } else { mdb_sql_error(sql, "Not connected."); } } MdbHandle *mdb_sql_open(MdbSQL *sql, char *db_name) { char *db_namep = db_name; #ifdef HAVE_WORDEXP wordexp_t words; if (wordexp(db_name, &words, 0)==0) { if (words.we_wordc>0) db_namep = words.we_wordv[0]; } #endif sql->mdb = mdb_open(db_namep, MDB_NOFLAGS); if ((!sql->mdb) && (!strstr(db_namep, ".mdb"))) { char *tmpstr = (char *) g_strconcat(db_namep, ".mdb", NULL); sql->mdb = mdb_open(tmpstr, MDB_NOFLAGS); g_free(tmpstr); } if (!sql->mdb) { mdb_sql_error(sql, "Unable to locate database %s", db_name); } #ifdef HAVE_WORDEXP wordfree(&words); #endif return sql->mdb; } MdbSargNode * mdb_sql_alloc_node() { return (MdbSargNode *) g_malloc0(sizeof(MdbSargNode)); } void mdb_sql_free_tree(MdbSargNode *tree) { if (tree->left) mdb_sql_free_tree(tree->left); if (tree->right) mdb_sql_free_tree(tree->right); if (tree->parent) g_free(tree->parent); g_free(tree); } void mdb_sql_push_node(MdbSQL *sql, MdbSargNode *node) { sql->sarg_stack = g_list_append(sql->sarg_stack, node); /* * Tree builds from bottom to top, so we should be left with * the correct tree root when done */ sql->sarg_tree = node; } MdbSargNode * mdb_sql_pop_node(MdbSQL *sql) { GList *glist; MdbSargNode *node; glist = g_list_last(sql->sarg_stack); if (!glist) return NULL; node = glist->data; #if 0 if (node->op==MDB_EQUAL) printf("popping %d\n", node->value.i); else printf("popping %s\n", node->op == MDB_OR ? "OR" : "AND"); #endif sql->sarg_stack = g_list_remove(sql->sarg_stack, node); return node; } void mdb_sql_add_not(MdbSQL *sql) { MdbSargNode *node, *left; left = mdb_sql_pop_node(sql); if (!left) { mdb_sql_error(sql, "parse error near 'NOT'"); mdb_sql_reset(sql); return; } node = mdb_sql_alloc_node(); node->op = MDB_NOT; node->left = left; mdb_sql_push_node(sql, node); } void mdb_sql_add_or(MdbSQL *sql) { MdbSargNode *node, *left, *right; left = mdb_sql_pop_node(sql); right = mdb_sql_pop_node(sql); if (!left || !right) { mdb_sql_error(sql, "parse error near 'OR'"); mdb_sql_reset(sql); return; } node = mdb_sql_alloc_node(); node->op = MDB_OR; node->left = left; node->right = right; mdb_sql_push_node(sql, node); } void mdb_sql_add_and(MdbSQL *sql) { MdbSargNode *node, *left, *right; left = mdb_sql_pop_node(sql); right = mdb_sql_pop_node(sql); if (!left || !right) { mdb_sql_error(sql, "parse error near 'AND'"); mdb_sql_reset(sql); return; } node = mdb_sql_alloc_node(); node->op = MDB_AND; node->left = left; node->right = right; mdb_sql_push_node(sql, node); } void mdb_sql_dump_node(MdbSargNode *node, int level) { int i; int mylevel = level+1; if (!level) printf("root "); for (i=0;i"); switch (node->op) { case MDB_OR: printf(" or\n"); break; case MDB_AND: printf(" and\n"); break; case MDB_NOT: printf(" not\n"); break; case MDB_LT: printf(" < %d\n", node->value.i); break; case MDB_GT: printf(" < %d\n", node->value.i); break; case MDB_LIKE: printf(" like %s\n", node->value.s); break; case MDB_EQUAL: printf(" = %d\n", node->value.i); break; } if (node->left) { printf("left "); mdb_sql_dump_node(node->left, mylevel); } if (node->right) { printf("right "); mdb_sql_dump_node(node->right, mylevel); } } /* evaluate a expression involving 2 constants and add answer to the stack */ int mdb_sql_eval_expr(MdbSQL *sql, char *const1, int op, char *const2) { long val1, val2, value, compar; unsigned char illop = 0; MdbSargNode *node; if (const1[0]=='\'' && const2[0]=='\'') { value = strcmp(const1, const2); switch (op) { case MDB_EQUAL: compar = (value ? 0 : 1); break; case MDB_GT: compar = (value > 0); break; case MDB_GTEQ: compar = (value >= 0); break; case MDB_LT: compar = (value < 0); break; case MDB_LTEQ: compar = (value <= 0); break; case MDB_LIKE: compar = mdb_like_cmp(const1,const2); break; default: illop = 1; } } else if (const1[0]!='\'' && const2[0]!='\'') { val1 = atol(const1); val2 = atol(const2); switch (op) { case MDB_EQUAL: compar = (val1 == val2); break; case MDB_GT: compar = (val1 > val2); break; case MDB_GTEQ: compar = (val1 >= val2); break; case MDB_LT: compar = (val1 < val2); break; case MDB_LTEQ: compar = (val1 <= val2); break; default: illop = 1; } } else { mdb_sql_error(sql, "Comparison of strings and numbers not allowed."); /* the column and table names are no good now */ mdb_sql_reset(sql); return 1; } if (illop) { mdb_sql_error(sql, "Illegal operator used for comparision of literals."); /* the column and table names are no good now */ mdb_sql_reset(sql); return 1; } node = mdb_sql_alloc_node(); node->op = MDB_EQUAL; node->col = NULL; node->value.i = (compar ? 1 : 0); mdb_sql_push_node(sql, node); return 0; } int mdb_sql_add_sarg(MdbSQL *sql, char *col_name, int op, char *constant) { int lastchar; MdbSargNode *node; node = mdb_sql_alloc_node(); node->op = op; /* stash the column name until we finish with the grammar */ node->parent = (void *) g_strdup(col_name); if (!constant) { /* XXX - do we need to check operator? */ mdb_sql_push_node(sql, node); return 0; } /* FIX ME -- we should probably just be storing the ascii value until the ** column definition can be checked for validity */ if (constant[0]=='\'') { lastchar = strlen(constant) > 256 ? 256 : strlen(constant); strncpy(node->value.s, &constant[1], lastchar - 2);; node->value.s[lastchar - 1]='\0'; } else { node->value.i = atoi(constant); } mdb_sql_push_node(sql, node); return 0; } void mdb_sql_all_columns(MdbSQL *sql) { sql->all_columns=1; } int mdb_sql_add_column(MdbSQL *sql, char *column_name) { MdbSQLColumn *c; c = (MdbSQLColumn *) g_malloc0(sizeof(MdbSQLColumn)); c->name = g_strdup(column_name); g_ptr_array_add(sql->columns, c); sql->num_columns++; return 0; } int mdb_sql_add_table(MdbSQL *sql, char *table_name) { MdbSQLTable *t; t = (MdbSQLTable *) g_malloc0(sizeof(MdbSQLTable)); t->name = g_strdup(table_name); t->alias = NULL; g_ptr_array_add(sql->tables, t); sql->num_tables++; return 0; } void mdb_sql_dump(MdbSQL *sql) { unsigned int i; MdbSQLColumn *c; MdbSQLTable *t; for (i=0;inum_columns;i++) { c = g_ptr_array_index(sql->columns,i); printf("column = %s\n",c->name); } for (i=0;inum_tables;i++) { t = g_ptr_array_index(sql->tables,i); printf("table = %s\n",t->name); } } void mdb_sql_exit(MdbSQL *sql) { mdb_sql_reset(sql); // Free memory if (sql->mdb) mdb_close(sql->mdb); } void mdb_sql_reset(MdbSQL *sql) { if (sql->cur_table) { mdb_index_scan_free(sql->cur_table); if (sql->cur_table->sarg_tree) { mdb_sql_free_tree(sql->cur_table->sarg_tree); sql->cur_table->sarg_tree = NULL; } mdb_free_tabledef(sql->cur_table); sql->cur_table = NULL; } /* Reset columns */ mdb_sql_free_columns(sql->columns); sql->num_columns = 0; sql->columns = g_ptr_array_new(); /* Reset tables */ mdb_sql_free_tables(sql->tables); sql->num_tables = 0; sql->tables = g_ptr_array_new(); /* Reset sargs */ if (sql->sarg_tree) { mdb_sql_free_tree(sql->sarg_tree); sql->sarg_tree = NULL; } g_list_free(sql->sarg_stack); sql->sarg_stack = NULL; sql->all_columns = 0; sql->max_rows = -1; } static void print_break(int sz, int first) { int i; if (first) { fprintf(stdout,"+"); } for (i=0;i= vlen ? ' ' : v[i]); } fprintf(stdout,"|"); } void mdb_sql_listtables(MdbSQL *sql) { unsigned int i; MdbCatalogEntry *entry; MdbHandle *mdb = sql->mdb; MdbField fields[1]; unsigned char row_buffer[MDB_PGSIZE]; int row_size; MdbTableDef *ttable; gchar tmpstr[100]; int tmpsiz; if (!mdb) { mdb_sql_error(sql, "You must connect to a database first"); return; } mdb_read_catalog (mdb, MDB_TABLE); ttable = mdb_create_temp_table(mdb, "#listtables"); mdb_sql_add_temp_col(sql, ttable, 0, "Tables", MDB_TEXT, 30, 0); /* add all user tables in catalog to list */ for (i=0; i < mdb->num_catalog; i++) { entry = g_ptr_array_index (mdb->catalog, i); if (mdb_is_user_table(entry)) { //col = g_ptr_array_index(table->columns,0); tmpsiz = mdb_ascii2unicode(mdb, entry->object_name, 0, tmpstr, 100); mdb_fill_temp_field(&fields[0],tmpstr, tmpsiz, 0,0,0,0); row_size = mdb_pack_row(ttable, row_buffer, 1, fields); mdb_add_row_to_pg(ttable,row_buffer, row_size); ttable->num_rows++; } } sql->cur_table = ttable; } int mdb_sql_add_temp_col(MdbSQL *sql, MdbTableDef *ttable, int col_num, char *name, int col_type, int col_size, int is_fixed) { MdbColumn tcol; MdbSQLColumn *sqlcol; mdb_fill_temp_col(&tcol, name, col_size, col_type, is_fixed); mdb_temp_table_add_col(ttable, &tcol); mdb_sql_add_column(sql, name); sqlcol = g_ptr_array_index(sql->columns,col_num); sqlcol->disp_size = mdb_col_disp_size(&tcol); return 0; } void mdb_sql_describe_table(MdbSQL *sql) { MdbTableDef *ttable, *table = NULL; MdbSQLTable *sql_tab; MdbHandle *mdb = sql->mdb; MdbColumn *col; unsigned int i; MdbField fields[3]; char tmpstr[256]; unsigned char row_buffer[MDB_PGSIZE]; int row_size; gchar col_name[100], col_type[100], col_size[100]; int tmpsiz; if (!mdb) { mdb_sql_error(sql, "You must connect to a database first"); return; } sql_tab = g_ptr_array_index(sql->tables,0); table = mdb_read_table_by_name(mdb, sql_tab->name, MDB_TABLE); if (!table) { mdb_sql_error(sql, "%s is not a table in this database", sql_tab->name); /* the column and table names are no good now */ mdb_sql_reset(sql); return; } mdb_read_columns(table); ttable = mdb_create_temp_table(mdb, "#describe"); mdb_sql_add_temp_col(sql, ttable, 0, "Column Name", MDB_TEXT, 30, 0); mdb_sql_add_temp_col(sql, ttable, 1, "Type", MDB_TEXT, 20, 0); mdb_sql_add_temp_col(sql, ttable, 2, "Size", MDB_TEXT, 10, 0); for (i=0;inum_cols;i++) { col = g_ptr_array_index(table->columns,i); tmpsiz = mdb_ascii2unicode(mdb, col->name, 0, col_name, 100); mdb_fill_temp_field(&fields[0],col_name, tmpsiz, 0,0,0,0); strcpy(tmpstr, mdb_get_colbacktype_string(col)); tmpsiz = mdb_ascii2unicode(mdb, tmpstr, 0, col_type, 100); mdb_fill_temp_field(&fields[1],col_type, tmpsiz, 0,0,0,1); sprintf(tmpstr,"%d",col->col_size); tmpsiz = mdb_ascii2unicode(mdb, tmpstr, 0, col_size, 100); mdb_fill_temp_field(&fields[2],col_size, tmpsiz, 0,0,0,2); row_size = mdb_pack_row(ttable, row_buffer, 3, fields); mdb_add_row_to_pg(ttable,row_buffer, row_size); ttable->num_rows++; } /* the column and table names are no good now */ //mdb_sql_reset(sql); sql->cur_table = ttable; } int mdb_sql_find_sargcol(MdbSargNode *node, gpointer data) { MdbTableDef *table = data; unsigned int i; MdbColumn *col; if (!mdb_is_relational_op(node->op)) return 0; if (!node->parent) return 0; for (i=0;inum_cols;i++) { col=g_ptr_array_index(table->columns,i); if (!strcasecmp(col->name, (char *)node->parent)) { node->col = col; break; } } return 0; } void mdb_sql_select(MdbSQL *sql) { unsigned int i,j; MdbHandle *mdb = sql->mdb; MdbTableDef *table = NULL; MdbSQLTable *sql_tab; MdbColumn *col; MdbSQLColumn *sqlcol; int found = 0; if (!mdb) { mdb_sql_error(sql, "You must connect to a database first"); return; } sql_tab = g_ptr_array_index(sql->tables,0); table = mdb_read_table_by_name(mdb, sql_tab->name, MDB_TABLE); if (!table) { mdb_sql_error(sql, "%s is not a table in this database", sql_tab->name); /* the column and table names are no good now */ mdb_sql_reset(sql); return; } mdb_read_columns(table); mdb_read_indices(table); mdb_rewind_table(table); if (sql->all_columns) { for (i=0;inum_cols;i++) { col = g_ptr_array_index(table->columns,i); mdb_sql_add_column(sql, col->name); } } /* verify all specified columns exist in this table */ for (i=0;inum_columns;i++) { sqlcol = g_ptr_array_index(sql->columns,i); found=0; for (j=0;jnum_cols;j++) { col=g_ptr_array_index(table->columns,j); if (!strcasecmp(sqlcol->name, col->name)) { sqlcol->disp_size = mdb_col_disp_size(col); found=1; break; } } if (!found) { mdb_sql_error(sql, "Column %s not found",sqlcol->name); mdb_sql_reset(sql); return; } } /* * resolve column names to MdbColumn structs */ if (sql->sarg_tree) { mdb_sql_walk_tree(sql->sarg_tree, mdb_sql_find_sargcol, table); mdb_sql_walk_tree(sql->sarg_tree, mdb_find_indexable_sargs, NULL); } /* * move the sarg_tree. * XXX - this won't work when we implement joins */ table->sarg_tree = sql->sarg_tree; sql->sarg_tree = NULL; sql->cur_table = table; mdb_index_scan_init(mdb, table); } void mdb_sql_bind_column(MdbSQL *sql, int colnum, void *varaddr, int *len_ptr) { MdbSQLColumn *sqlcol; /* sql columns are traditionally 1 based, so decrement colnum */ sqlcol = g_ptr_array_index(sql->columns,colnum - 1); mdb_bind_column_by_name(sql->cur_table, sqlcol->name, varaddr, len_ptr); } void mdb_sql_bind_all(MdbSQL *sql) { unsigned int i; for (i=0;inum_columns;i++) { sql->bound_values[i] = g_malloc0(MDB_BIND_SIZE); mdb_sql_bind_column(sql, i+1, sql->bound_values[i], NULL); } } /* * mdb_sql_fetch_row is now just a wrapper around mdb_fetch_row. * It is left here only for backward compatibility. */ int mdb_sql_fetch_row(MdbSQL *sql, MdbTableDef *table) { return mdb_fetch_row(table); } void mdb_sql_dump_results(MdbSQL *sql) { unsigned int j; MdbSQLColumn *sqlcol; /* print header */ for (j=0;jnum_columns;j++) { sqlcol = g_ptr_array_index(sql->columns,j); print_break(sqlcol->disp_size, !j); } fprintf(stdout,"\n"); for (j=0;jnum_columns;j++) { sqlcol = g_ptr_array_index(sql->columns,j); print_value(sqlcol->name,sqlcol->disp_size,!j); } fprintf(stdout,"\n"); for (j=0;jnum_columns;j++) { sqlcol = g_ptr_array_index(sql->columns,j); print_break(sqlcol->disp_size, !j); } fprintf(stdout,"\n"); /* print each row */ while(mdb_fetch_row(sql->cur_table)) { for (j=0;jnum_columns;j++) { sqlcol = g_ptr_array_index(sql->columns,j); print_value(sql->bound_values[j],sqlcol->disp_size,!j); } fprintf(stdout,"\n"); } /* footer */ for (j=0;jnum_columns;j++) { sqlcol = g_ptr_array_index(sql->columns,j); print_break(sqlcol->disp_size, !j); } fprintf(stdout,"\n"); /* clean up */ for (j=0;jnum_columns;j++) { g_free(sql->bound_values[j]); } /* the column and table names are no good now */ mdb_sql_reset(sql); } mdbtools-0.7.1/src/sql/parser.y000066400000000000000000000061261222645741400164320ustar00rootroot00000000000000%{ /* MDB Tools - A library for reading MS Access database files * Copyright (C) 2000 Brian Bruns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "mdbsql.h" int yylex(void); int yyerror(char *); MdbSQL *_mdb_sql(MdbSQL *sql) { static MdbSQL *g_sql; if (sql) { g_sql = sql; } return g_sql; } %} %union { char *name; double dval; int ival; } %token IDENT NAME PATH STRING NUMBER %token SELECT FROM WHERE CONNECT DISCONNECT TO LIST TABLES AND OR NOT %token DESCRIBE TABLE %token LTEQ GTEQ LIKE IS NUL %type database %type constant %type operator %type nulloperator %type identifier %% stmt: query | error { yyclearin; mdb_sql_reset(_mdb_sql(NULL)); } ; query: SELECT column_list FROM table where_clause { mdb_sql_select(_mdb_sql(NULL)); } | CONNECT TO database { mdb_sql_open(_mdb_sql(NULL), $3); free($3); } | DISCONNECT { mdb_sql_close(_mdb_sql(NULL)); } | DESCRIBE TABLE table { mdb_sql_describe_table(_mdb_sql(NULL)); } | LIST TABLES { mdb_sql_listtables(_mdb_sql(NULL)); } ; where_clause: /* empty */ | WHERE sarg_list ; sarg_list: sarg | '(' sarg_list ')' | NOT sarg_list { mdb_sql_add_not(_mdb_sql(NULL)); } | sarg_list OR sarg_list { mdb_sql_add_or(_mdb_sql(NULL)); } | sarg_list AND sarg_list { mdb_sql_add_and(_mdb_sql(NULL)); } ; sarg: identifier operator constant { mdb_sql_add_sarg(_mdb_sql(NULL), $1, $2, $3); free($1); free($3); } | constant operator identifier { mdb_sql_add_sarg(_mdb_sql(NULL), $3, $2, $1); free($1); free($3); } | constant operator constant { mdb_sql_eval_expr(_mdb_sql(NULL), $1, $2, $3); free($1); free($3); } | identifier nulloperator { mdb_sql_add_sarg(_mdb_sql(NULL), $1, $2, NULL); free($1); } ; identifier: NAME | IDENT ; operator: '=' { $$ = MDB_EQUAL; } | '>' { $$ = MDB_GT; } | '<' { $$ = MDB_LT; } | LTEQ { $$ = MDB_LTEQ; } | GTEQ { $$ = MDB_GTEQ; } | LIKE { $$ = MDB_LIKE; } ; nulloperator: IS NUL { $$ = MDB_ISNULL; } | IS NOT NUL { $$ = MDB_NOTNULL; } ; constant: NUMBER { $$ = $1; } | STRING { $$ = $1; } ; database: PATH | NAME ; table: identifier { mdb_sql_add_table(_mdb_sql(NULL), $1); free($1); } ; column_list: '*' { mdb_sql_all_columns(_mdb_sql(NULL)); } | column | column ',' column_list ; column: identifier { mdb_sql_add_column(_mdb_sql(NULL), $1); free($1); } ; %% mdbtools-0.7.1/src/util/000077500000000000000000000000001222645741400151155ustar00rootroot00000000000000mdbtools-0.7.1/src/util/Makefile.am000066400000000000000000000006641222645741400171570ustar00rootroot00000000000000bin_PROGRAMS = mdb-export mdb-array mdb-schema mdb-tables mdb-parsecsv mdb-header mdb-sql mdb-ver mdb-prop noinst_PROGRAMS = mdb-import prtable prcat prdata prkkd prdump prole updrow prindex LIBS = $(GLIB_LIBS) @LIBS@ @LEXLIB@ DEFS = @DEFS@ -DLOCALEDIR=\"$(localedir)\" AM_CFLAGS = -I$(top_srcdir)/include $(GLIB_CFLAGS) LDADD = ../libmdb/libmdb.la if SQL mdb_sql_LDADD = ../libmdb/libmdb.la ../sql/libmdbsql.la $(LIBREADLINE) endif mdbtools-0.7.1/src/util/mdb-array.c000066400000000000000000000064731222645741400171510ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * 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. */ /* this is inherited from mdb-export.c, modified to make arrays similar to those generated by parsecsv.c */ #include "mdbtools.h" #ifdef DMALLOC #include "dmalloc.h" #endif int main (int argc, char **argv) { unsigned int j; MdbHandle *mdb; MdbTableDef *table; MdbColumn *col; /* doesn't handle tables > 256 columns. Can that happen? */ char *bound_values [256]; char delimiter [] = ", "; char quote_text = 1; int count = 0; int started; if (argc < 3) { fprintf (stderr, "Usage: %s
    \n", argv [0]); exit (1); } mdb = mdb_open (argv [1], MDB_NOFLAGS); if (!mdb) exit(1); table = mdb_read_table_by_name (mdb, argv[2], MDB_TABLE); if (table) { mdb_read_columns (table); mdb_rewind_table (table); for (j = 0; j < table->num_cols; j++) { bound_values [j] = (char *) g_malloc (MDB_BIND_SIZE); bound_values [j] [0] = '\0'; mdb_bind_column (table, j+1, bound_values[j], NULL); } fprintf (stdout, "/******************************************************************/\n"); fprintf (stdout, "/* THIS IS AN AUTOMATICALLY GENERATED FILE. DO NOT EDIT IT!!!!!! */\n"); fprintf (stdout, "/******************************************************************/\n"); fprintf (stdout, "\n"); fprintf (stdout, "#include \n"); fprintf (stdout, "#include \"types.h\"\n"); fprintf (stdout, "#include \"dump.h\"\n"); fprintf (stdout, "\n"); fprintf (stdout, "const %s %s_array [] = {\n", argv [2], argv [2]); count = 0; started = 0; while (mdb_fetch_row (table)) { if (started != 0) { fprintf (stdout, ",\n"); } started = 1; fprintf (stdout, "{\t\t\t\t/* %6d */\n\t", count); for (j = 0; j < table->num_cols; j++) { fprintf (stdout, "\t"); col = g_ptr_array_index (table->columns, j); if (quote_text && (col->col_type == MDB_TEXT || col->col_type == MDB_MEMO)) { fprintf (stdout, "\"%s\"", bound_values [j]); } else { fprintf (stdout, "%s", bound_values [j]); } if (j != table->num_cols - 1) { fprintf (stdout, "%s\n", delimiter); } else { fprintf (stdout, "\n"); } } fprintf (stdout, "}"); count++; } fprintf (stdout, "\n};\n\n"); for (j = 0; j < table->num_cols; j++) { g_free (bound_values [j]); } mdb_free_tabledef(table); } mdb_close (mdb); fprintf (stdout, "const int %s_array_length = %d;\n", argv [2], count); return 0; } mdbtools-0.7.1/src/util/mdb-check.c000066400000000000000000000046601222645741400171040ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * 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. */ /* this utility dumps the schema for an existing database */ #include "mdbtools.h" #ifdef DMALLOC #include "dmalloc.h" #endif int dbcc_page_usage(MdbTableDef *table) { } int dbcc_idx_page_usage(MdbTableDef *table) { } int dbcc_lost_pages(MdbTableDef *table) { } main (int argc, char **argv) { int i, j, k; MdbHandle *mdb; MdbCatalogEntry *entry; MdbTableDef *table; char *tabname = NULL; int opt; if (argc < 2) { fprintf (stderr, "Usage: %s [-T
    ]\n",argv[0]); exit (1); } while ((opt=getopt(argc, argv, "T:"))!=-1) { switch (opt) { case 'T': tabname = (char *) g_strdup(optarg); break; } } /* open the database */ mdb = mdb_open (argv[optind], MDB_NOFLAGS); /* read the catalog */ mdb_read_catalog (mdb, MDB_TABLE); /* loop over each entry in the catalog */ for (i=0; i < mdb->num_catalog; i++) { entry = g_ptr_array_index (mdb->catalog, i); /* if it's a table */ if (entry->object_type == MDB_TABLE) { if ((tabname && !strcmp(entry->object_name,tabname)) || (!tabname /* && mdb_is_user_table(entry) */)) { int ret; table = mdb_read_table(entry); /* get the columns */ mdb_read_columns(table); fprintf(stdout,"Check 1: Checking data page usage map\n"); ret = dbcc_page_usage(table); fprintf(stdout,"Check 1: %s\n", ret ? "Failed" : "Passed"); fprintf(stdout,"Check 2: Checking index page usage map\n"); fprintf(stdout,"Check 3: Checking for lost pages\n"); ret = dbcc_lost_pages(table); //check_ret(table, ret); mdb_free_tabledef(table); } } } g_free(tabname); mdb_close (mdb); return 0; } mdbtools-0.7.1/src/util/mdb-export.c000066400000000000000000000203421222645741400173430ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * 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. */ #include "mdbtools.h" #ifdef DMALLOC #include "dmalloc.h" #endif #undef MDB_BIND_SIZE #define MDB_BIND_SIZE 200000 #define is_quote_type(x) (x==MDB_TEXT || x==MDB_OLE || x==MDB_MEMO || x==MDB_DATETIME || x==MDB_BINARY || x==MDB_REPID) #define is_binary_type(x) (x==MDB_OLE || x==MDB_BINARY || x==MDB_REPID) static char *escapes(char *s); //#define DONT_ESCAPE_ESCAPE static void print_col(FILE *outfile, gchar *col_val, int quote_text, int col_type, int bin_len, char *quote_char, char *escape_char, int bin_mode) /* quote_text: Don't quote if 0. */ { size_t quote_len = strlen(quote_char); /* multibyte */ size_t orig_escape_len = escape_char ? strlen(escape_char) : 0; /* double the quote char if no escape char passed */ if (!escape_char) escape_char = quote_char; if (quote_text && is_quote_type(col_type)) { fputs(quote_char, outfile); while (1) { if (is_binary_type(col_type)) { if (bin_mode == MDB_BINEXPORT_STRIP) break; if (!bin_len--) break; } else /* use \0 sentry */ if (!*col_val) break; if (quote_len && !strncmp(col_val, quote_char, quote_len)) { fprintf(outfile, "%s%s", escape_char, quote_char); col_val += quote_len; #ifndef DONT_ESCAPE_ESCAPE } else if (orig_escape_len && !strncmp(col_val, escape_char, orig_escape_len)) { fprintf(outfile, "%s%s", escape_char, escape_char); col_val += orig_escape_len; #endif } else if (is_binary_type(col_type) && *col_val <= 0 && bin_mode == MDB_BINEXPORT_OCTAL) fprintf(outfile, "\\%03o", *(unsigned char*)col_val++); else putc(*col_val++, outfile); } fputs(quote_char, outfile); } else fputs(col_val, outfile); } int main(int argc, char **argv) { unsigned int i; MdbHandle *mdb; MdbTableDef *table; MdbColumn *col; char **bound_values; int *bound_lens; FILE *outfile = stdout; char *delimiter = NULL; char *row_delimiter = NULL; char *quote_char = NULL; char *escape_char = NULL; char header_row = 1; char quote_text = 1; char *insert_dialect = NULL; char *namespace = NULL; int bin_mode = MDB_BINEXPORT_RAW; int opt; char *value; size_t length; while ((opt=getopt(argc, argv, "HQq:X:d:D:R:I:N:b:"))!=-1) { switch (opt) { case 'H': header_row = 0; break; case 'Q': quote_text = 0; break; case 'q': quote_char = (char *) g_strdup(optarg); break; case 'd': delimiter = escapes(optarg); break; case 'R': row_delimiter = escapes(optarg); break; case 'I': insert_dialect = (char*) g_strdup(optarg); header_row = 0; break; case 'D': mdb_set_date_fmt(optarg); break; case 'X': escape_char = (char *) g_strdup(optarg); break; case 'N': namespace = (char *) g_strdup(optarg); break; case 'b': if (!strcmp(optarg, "strip")) bin_mode = MDB_BINEXPORT_STRIP; else if (!strcmp(optarg, "raw")) bin_mode = MDB_BINEXPORT_RAW; else if (!strcmp(optarg, "octal")) bin_mode = MDB_BINEXPORT_OCTAL; else { fprintf(stderr, "Invalid binary mode\n"); exit(1); } break; default: break; } } if (!quote_char) { quote_char = (char *) g_strdup("\""); } if (!delimiter) { delimiter = (char *) g_strdup(","); } if (!row_delimiter) { row_delimiter = (char *) g_strdup("\n"); } /* ** optind is now the position of the first non-option arg, ** see getopt(3) */ if (argc-optind < 2) { fprintf(stderr,"Usage: %s [options]
    \n",argv[0]); fprintf(stderr,"where options are:\n"); fprintf(stderr," -H supress header row\n"); fprintf(stderr," -Q don't wrap text-like fields in quotes\n"); fprintf(stderr," -d specify a column delimiter\n"); fprintf(stderr," -R specify a row delimiter\n"); fprintf(stderr," -I INSERT statements (instead of CSV)\n"); fprintf(stderr," -D set the date format (see strftime(3) for details)\n"); fprintf(stderr," -q Use to wrap text-like fields. Default is \".\n"); fprintf(stderr," -X Use to escape quoted characters within a field. Default is doubling.\n"); fprintf(stderr," -N Prefix identifiers with namespace\n"); fprintf(stderr," -b strip|raw|octal Binary export mode.\n"); g_free (delimiter); g_free (row_delimiter); g_free (quote_char); if (escape_char) g_free (escape_char); exit(1); } if (!(mdb = mdb_open(argv[optind], MDB_NOFLAGS))) { g_free (delimiter); g_free (row_delimiter); g_free (quote_char); if (escape_char) g_free (escape_char); exit(1); } if (insert_dialect) if (!mdb_set_default_backend(mdb, insert_dialect)) { fprintf(stderr, "Invalid backend type\n"); if (escape_char) g_free (escape_char); exit(1); } table = mdb_read_table_by_name(mdb, argv[argc-1], MDB_TABLE); if (!table) { fprintf(stderr, "Error: Table %s does not exist in this database.\n", argv[argc-1]); g_free (delimiter); g_free (row_delimiter); g_free (quote_char); if (escape_char) g_free (escape_char); mdb_close(mdb); exit(1); } /* read table */ mdb_read_columns(table); mdb_rewind_table(table); bound_values = (char **) g_malloc(table->num_cols * sizeof(char *)); bound_lens = (int *) g_malloc(table->num_cols * sizeof(int)); for (i=0;inum_cols;i++) { /* bind columns */ bound_values[i] = (char *) g_malloc0(MDB_BIND_SIZE); mdb_bind_column(table, i+1, bound_values[i], &bound_lens[i]); } if (header_row) { for (i=0; inum_cols; i++) { col=g_ptr_array_index(table->columns,i); if (i) fputs(delimiter, outfile); fputs(col->name, outfile); } fputs(row_delimiter, outfile); } while(mdb_fetch_row(table)) { if (insert_dialect) { char *quoted_name; quoted_name = mdb->default_backend->quote_schema_name(namespace, argv[optind + 1]); fprintf(outfile, "INSERT INTO %s (", quoted_name); free(quoted_name); for (i=0;inum_cols;i++) { if (i>0) fputs(", ", outfile); col=g_ptr_array_index(table->columns,i); quoted_name = mdb->default_backend->quote_schema_name(NULL, col->name); fputs(quoted_name, outfile); free(quoted_name); } fputs(") VALUES (", outfile); } for (i=0;inum_cols;i++) { if (i>0) fputs(delimiter, outfile); col=g_ptr_array_index(table->columns,i); if (!bound_lens[i]) { /* Don't quote NULLs */ if (insert_dialect) fputs("NULL", outfile); } else { if (col->col_type == MDB_OLE) { value = mdb_ole_read_full(mdb, col, &length); } else { value = bound_values[i]; length = bound_lens[i]; } print_col(outfile, value, quote_text, col->col_type, length, quote_char, escape_char, bin_mode); if (col->col_type == MDB_OLE) free(value); } } if (insert_dialect) fputs(");", outfile); fputs(row_delimiter, outfile); } /* free the memory used to bind */ for (i=0;inum_cols;i++) { g_free(bound_values[i]); } g_free(bound_values); g_free(bound_lens); mdb_free_tabledef(table); g_free (delimiter); g_free (row_delimiter); g_free (quote_char); if (escape_char) g_free (escape_char); mdb_close(mdb); return 0; } static char *escapes(char *s) { char *d = (char *) g_strdup(s); char *t = d; unsigned char encode = 0; for (;*s; s++) { if (encode) { switch (*s) { case 'n': *t++='\n'; break; case 't': *t++='\t'; break; case 'r': *t++='\r'; break; default: *t++='\\'; *t++=*s; break; } encode=0; } else if (*s=='\\') { encode=1; } else { *t++=*s; } } *t='\0'; return d; } mdbtools-0.7.1/src/util/mdb-header.c000066400000000000000000000103271222645741400172540ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * 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. */ /* this utility dumps the C headers for an existing database */ /* it will create three files - types.h and dump_types.[ch] */ #include #include "mdbtools.h" #ifdef DMALLOC #include "dmalloc.h" #endif void copy_header (FILE *f) { fprintf (f, "/******************************************************************/\n"); fprintf (f, "/* THIS IS AN AUTOMATICALLY GENERATED FILE. DO NOT EDIT IT!!!!!! */\n"); fprintf (f, "/******************************************************************/\n"); } int main (int argc, char **argv) { unsigned int i, j, k; unsigned int unsupported = 0; MdbHandle *mdb; MdbCatalogEntry *entry; MdbTableDef *table; MdbColumn *col; FILE *typesfile; FILE *headerfile; FILE *cfile; if (argc < 2) { fprintf (stderr, "Usage: %s \n",argv[0]); exit (1); } /* open the database */ mdb = mdb_open (argv[1], MDB_NOFLAGS); if (!mdb) { exit(1); } typesfile = fopen ("types.h", "w"); headerfile = fopen ("dumptypes.h", "w"); cfile = fopen ("dumptypes.c", "w"); copy_header (typesfile); copy_header (headerfile); fprintf (headerfile, "#include \"types.h\"\n"); copy_header (cfile); fprintf (cfile, "#include \n"); fprintf (cfile, "#include \"dumptypes.h\"\n"); /* read the catalog */ mdb_read_catalog (mdb, MDB_TABLE); /* loop over each entry in the catalog */ for (i=0; i < mdb->num_catalog; i++) { entry = g_ptr_array_index (mdb->catalog, i); if (!mdb_is_user_table(entry)) continue; fprintf (typesfile, "typedef struct _%s\n", entry->object_name); fprintf (typesfile, "{\n"); fprintf (headerfile, "void dump_%s (%s x);\n", entry->object_name, entry->object_name); fprintf (cfile, "void dump_%s (%s x)\n{\n", entry->object_name, entry->object_name); fprintf (cfile, "\tfprintf (stdout, \"**************** %s ****************\\n\");\n", entry->object_name); table = mdb_read_table (entry); /* get the columns */ mdb_read_columns (table); /* loop over the columns, dumping the names and types */ for (k = 0; k < table->num_cols; k++) { col = g_ptr_array_index (table->columns, k); fprintf (cfile, "\tfprintf (stdout, \"x."); for (j = 0; j < strlen (col->name); j++) { fprintf (cfile, "%c", tolower (col->name [j])); } fprintf (cfile, " = \");\n"); switch (col->col_type) { case MDB_INT: fprintf (typesfile, "\tint\t"); fprintf (cfile, "\tdump_int (x."); break; case MDB_LONGINT: fprintf (typesfile, "\tlong\t"); fprintf (cfile, "\tdump_long (x."); break; case MDB_TEXT: case MDB_MEMO: fprintf (typesfile, "\tchar *\t"); fprintf (cfile, "\tdump_string (x."); break; default: unsupported = 1; break; } for (j = 0; j < strlen (col->name); j++) { fprintf (typesfile, "%c", tolower (col->name [j])); fprintf (cfile, "%c", tolower (col->name [j])); } fprintf (typesfile, ";\n"); fprintf (cfile, ");\n"); } fprintf (typesfile, "\n} %s ;\n", entry->object_name); fprintf (typesfile, "\n"); fprintf (cfile, "}\n\n"); mdb_free_tabledef(table); } fclose (headerfile); fclose (typesfile); fclose (cfile); mdb_close (mdb); if (unsupported) fputs("ERROR: unsupported type.\n", stderr); exit(unsupported); } mdbtools-0.7.1/src/util/mdb-import.c000066400000000000000000000130521222645741400173340ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * 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. */ #include "mdbtools.h" #define MAX_ROW_SIZE 4096 void free_values(MdbField *fields, int num_fields) { int i; for (i=0;icolnum = col->col_num; field->is_fixed = col->is_fixed; switch (col->col_type) { case MDB_TEXT: field->value = g_strdup(s); field->siz = strlen(s); break; case MDB_BYTE: any.i = strtol(s, &c, 16); if (*c) return 1; field->siz = mdb_col_fixed_size(col); field->value = g_malloc(field->siz); ((unsigned char *)field->value)[0] = any.i; break; case MDB_INT: any.i = strtol(s, &c, 16); if (*c) return 1; field->siz = mdb_col_fixed_size(col); field->value = g_malloc(field->siz); mdb_put_int16(field->value, 0, any.i); break; case MDB_LONGINT: any.i = strtol(s, &c, 16); if (*c) return 1; field->siz = mdb_col_fixed_size(col); field->value = g_malloc(field->siz); mdb_put_int32(field->value, 0, any.i); break; case MDB_BOOL: if (*s == '1') { field->is_null = 1; } else if (*s == '0') { field->is_null = 0; } else { fprintf(stderr, "%c is not a valid value for type BOOLEAN\n", *s); return 1; } /* case MDB_FLOAT: any.d = strtod(s, &c); if (*c) return 1; field.value = g_malloc(mdb_col_fixed_size(col)); mdb_put_single(field.value, 0, any.i); break; case MDB_DOUBLE: any.d = strtod(s, &c); if (*c) return 1; field.value = g_malloc(mdb_col_fixed_size(col)); mdb_put_double(field.value, 0, any.i); break; */ /* case MDB_MONEY: case MDB_SDATETIME: case MDB_OLE: case MDB_MEMO: case MDB_REPID: case MDB_NUMERIC: */ default: fprintf(stderr,"Conversion of type %02x not supported yet.\n", col->col_type); return 1; break; } return 0; } int prep_row(MdbTableDef *table, char *line, MdbField *fields, char *delim) { MdbColumn *col; char **sarray, *s; unsigned int i; /* * pull apart the row and turn it into something respectable */ g_strdelimit(line, delim, '\n'); sarray = g_strsplit (line, "\n", 0); for (i=0; (s = sarray[i]); i++) { if (!strlen(s)) continue; if (i >= table->num_cols) { fprintf(stderr, "Number of columns in file exceeds number in table.\n"); g_strfreev(sarray); return 0; } if (s[0]=='"' && s[strlen(s)-1]=='"') { s[strlen(s)-1] = '\0'; memmove(s+1, s, strlen(s)); } printf("field = %s\n", s); col = g_ptr_array_index (table->columns, i); if (convert_field(col, s, &fields[i])) { fprintf(stderr, "Format error in column %d\n", i+1); g_strfreev(sarray); return 0; } } g_strfreev(sarray); /* * verify number of columns in table against number in row */ if (i < table->num_cols) { fprintf(stderr, "Row has %d columns, but table has %d\n", i, table->num_cols); free_values(fields, i); return 0; } return i-1; } int main(int argc, char **argv) { int i, row; MdbHandle *mdb; MdbTableDef *table; MdbField fields[256]; char line[MAX_ROW_SIZE]; int num_fields; /* doesn't handle tables > 256 columns. Can that happen? */ int opt; FILE *in; char delimiter[2] = ","; char header_rows = 0; while ((opt=getopt(argc, argv, "H:d:"))!=-1) { switch (opt) { case 'H': header_rows = atol(optarg); break; case 'd': delimiter[0] = optarg[0]; break; default: break; } } /* ** optind is now the position of the first non-option arg, ** see getopt(3) */ if (argc-optind < 3) { fprintf(stderr,"Usage: %s [options]
    \n",argv[0]); fprintf(stderr,"where options are:\n"); fprintf(stderr," -H skip header rows\n"); fprintf(stderr," -d specify a column delimiter\n"); exit(1); } if (!(mdb = mdb_open(argv[optind], MDB_WRITABLE))) { exit(1); } table = mdb_read_table_by_name(mdb, argv[argc-2], MDB_TABLE); if (!table) { fprintf(stderr,"Table %s not found in database\n", argv[argc-2]); exit(1); } mdb_read_columns(table); mdb_read_indices(table); mdb_rewind_table(table); /* * open the CSV file and read any header rows */ in = fopen(argv[argc-1], "r"); if (!in) { fprintf(stderr, "Can not open file %s\n", argv[argc-1]); exit(1); } for (i=0;i #include #include #ifdef DMALLOC #include "dmalloc.h" #endif #define FILENAMESIZE 128 #define BUFFERSIZE 4096 #define LF 10 #define NL 13 #define TRUE 1 #define FALSE 0 void copy_header (FILE *f) { fprintf (f, "/******************************************************************/\n"); fprintf (f, "/* THIS IS AN AUTOMATICALLY GENERATED FILE. DO NOT EDIT IT!!!!!! */\n"); fprintf (f, "/******************************************************************/\n"); } int main (int argc, char **argv) { char txt_filename [FILENAMESIZE]; char c_filename [FILENAMESIZE]; FILE *txtfile; FILE *cfile; int count; char input [BUFFERSIZE]; int location; int c; int instring; int lastcomma; int i; if (argc < 2) { fprintf (stderr, "Usage: %s (assumed extension .txt)\n",argv[0]); exit (1); } strcpy (txt_filename, argv [1]); txtfile = fopen (txt_filename, "r"); if (!txtfile) { strcat (txt_filename, ".txt"); txtfile = fopen (txt_filename, "r"); if (!txtfile) exit(1); } else { /* strip away extension */ for (i=strlen(txt_filename);i > 0 && txt_filename[i]!='.';i--); if (txt_filename[i]=='.') txt_filename[i]='\0'; } strcpy (c_filename, argv [1]); strcat (c_filename, ".c"); cfile = fopen (c_filename, "w"); copy_header (cfile); fprintf (cfile, "\n"); fprintf (cfile, "#include \n"); fprintf (cfile, "#include \"types.h\"\n"); fprintf (cfile, "#include \"mdbsupport.h\"\n"); fprintf (cfile, "\n"); fprintf (cfile, "const %s %s_array [] = {\n", argv [1], argv [1]); c = 0; count = 0; while (c != -1) { location = 0; memset (input, 0, BUFFERSIZE); while ((c = fgetc (txtfile)) != NL) { if (c == -1) break; input [location++] = c; } input [location] = '\0'; if (location > 0) { if (count != 0) { fprintf (cfile, ",\n"); } fprintf (cfile, "{\t\t\t\t/* %6d */\n\t", count); instring = FALSE; lastcomma = FALSE; for (i = 0; i < location; i++) { if (instring) { if (input [i] == '\\') fprintf (cfile, "\\\\"); else if (input [i] == LF) fprintf (cfile, "\\n"); else if (input [i] != NL) fprintf (cfile, "%c", input [i]); if (input [i] == '"') { instring = FALSE; lastcomma = FALSE; } } else { switch (input [i]) { case ',': if (lastcomma) fprintf (cfile, "\"\""); fprintf (cfile, ",\n\t"); lastcomma = TRUE; break; case '"': fprintf (cfile, "%c", input [i]); lastcomma = FALSE; instring = TRUE; break; default: fprintf (cfile, "%c", input [i]); lastcomma = FALSE; break; } } } if (lastcomma) fprintf (cfile, "\"\"\n"); fprintf (cfile, "\n}"); count++; } c = fgetc (txtfile); } fprintf (cfile, "\n};\n"); fprintf (cfile, "\nconst int %s_array_length = %d;\n", argv [1], count); fclose (txtfile); fclose (cfile); fprintf (stdout, "count = %d\n", count); return 0; } mdbtools-0.7.1/src/util/mdb-prop.c000066400000000000000000000046571222645741400170150ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000-2011 Brian Bruns and others * * 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. */ #include "mdbtools.h" void dump_kkd(MdbHandle *mdb, void *kkd, size_t len); int main(int argc, char **argv) { MdbHandle *mdb; MdbTableDef *table; gchar name[256]; gchar *propColName; void *buf; int col_num; int found = 0; if (argc < 3) { fprintf(stderr,"Usage: %s []\n", argv[0]); return 1; } if (argc < 4) propColName = "LvProp"; else propColName = argv[3]; mdb = mdb_open(argv[1], MDB_NOFLAGS); if (!mdb) { return 1; } table = mdb_read_table_by_name(mdb, "MSysObjects", MDB_ANY); if (!table) { mdb_close(mdb); return 1; } mdb_read_columns(table); mdb_rewind_table(table); mdb_bind_column_by_name(table, "Name", name, NULL); buf = g_malloc(MDB_BIND_SIZE); col_num = mdb_bind_column_by_name(table, propColName, buf, NULL); if (col_num < 1) { g_free(buf); mdb_free_tabledef(table); mdb_close(mdb); printf("Column %s not found in MSysObjects!\n", argv[3]); return 1; } while(mdb_fetch_row(table)) { if (!strcmp(name, argv[2])) { found = 1; break; } } if (found) { MdbColumn *col = g_ptr_array_index(table->columns, col_num-1); size_t size; void *kkd = mdb_ole_read_full(mdb, col, &size); if (size) dump_kkd(mdb, kkd, size); else printf("No properties.\n"); free(kkd); } g_free(buf); mdb_free_tabledef(table); mdb_close(mdb); return 0; } void dump_kkd(MdbHandle *mdb, void *kkd, size_t len) { GArray *aprops = mdb_kkd_to_props(mdb, kkd, len); int i; if (!aprops) return; for (i=0; ilen; ++i) { MdbProperties *props = g_array_index(aprops, MdbProperties*, i); mdb_dump_props(props, stdout, 1); } } mdbtools-0.7.1/src/util/mdb-schema.c000066400000000000000000000114561222645741400172700ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * 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. */ /* this utility dumps the schema for an existing database */ #include #include #include "mdbtools.h" #ifdef DMALLOC #include "dmalloc.h" #endif int main (int argc, char **argv) { MdbHandle *mdb; char *tabname = NULL; char *namespace = NULL; guint32 export_options = MDB_SHEXP_DEFAULT; int opt; if (argc < 2) { fprintf (stderr, "Usage: %s [options] []\n",argv[0]); fprintf (stderr, "where options are:\n"); fprintf (stderr, " -T
    Only create schema for named table\n"); fprintf (stderr, " -N Prefix identifiers with namespace\n"); exit (1); } while (1) { //int this_option_optind = optind ? optind : 1; int option_index = 0; static struct option long_options[] = { {"table", 1, NULL, 'T'}, {"namespace", 1, NULL, 'N'}, {"drop-table", 0, NULL, 0}, {"no-drop-table", 0, NULL, 0}, {"default-values", 0, NULL, 0}, {"no-default-values", 0, NULL, 0}, {"not-null", 0, NULL, 0}, {"no-not-null", 0, NULL, 0}, {"not-empty", 0, NULL, 0}, {"no-not-empty", 0, NULL, 0}, {"description", 0, NULL, 0}, {"no-description", 0, NULL, 0}, {"indexes", 0, NULL, 0}, {"no-indexes", 0, NULL, 0}, {"relations", 0, NULL, 0}, {"no-relations", 0, NULL, 0}, {NULL, 0, NULL, 0}, }; opt = getopt_long(argc, argv, "T:N:", long_options, &option_index); if (opt == -1) break; switch (opt) { case 0: if (!strcmp(long_options[option_index].name, "drop-table")) { export_options |= MDB_SHEXP_DROPTABLE; break; } if (!strcmp(long_options[option_index].name, "no-drop-table")) { export_options &= ~MDB_SHEXP_DROPTABLE; break; } if (!strcmp(long_options[option_index].name, "not-null")) { export_options |= MDB_SHEXP_CST_NOTNULL; break; } if (!strcmp(long_options[option_index].name, "no-not-null")) { export_options &= ~MDB_SHEXP_CST_NOTNULL; break; } if (!strcmp(long_options[option_index].name, "default-values")) { export_options |= MDB_SHEXP_DEFVALUES; break; } if (!strcmp(long_options[option_index].name, "no-default-values")) { export_options &= ~MDB_SHEXP_DEFVALUES; break; } if (!strcmp(long_options[option_index].name, "not-empty")) { export_options |= MDB_SHEXP_CST_NOTEMPTY; break; } if (!strcmp(long_options[option_index].name, "no-not-empty")) { export_options &= ~MDB_SHEXP_CST_NOTEMPTY; break; } if (!strcmp(long_options[option_index].name, "description")) { export_options |= MDB_SHEXP_COMMENTS; break; } if (!strcmp(long_options[option_index].name, "no-description")) { export_options &= ~MDB_SHEXP_COMMENTS; break; } if (!strcmp(long_options[option_index].name, "indexes")) { export_options |= MDB_SHEXP_INDEXES; break; } if (!strcmp(long_options[option_index].name, "no-indexes")) { export_options &= ~MDB_SHEXP_INDEXES; break; } if (!strcmp(long_options[option_index].name, "relations")) { export_options |= MDB_SHEXP_RELATIONS; break; } if (!strcmp(long_options[option_index].name, "no-relations")) { export_options &= ~MDB_SHEXP_RELATIONS; break; } fprintf(stderr, "unimplemented option %s", long_options[option_index].name); if (optarg) fprintf(stderr, " with arg %s", optarg); fputc('\n', stderr); exit(1); break; case 'T': tabname = (char *) g_strdup(optarg); break; case 'N': namespace = (char *) g_strdup(optarg); break; } } /* open the database */ mdb = mdb_open (argv[optind], MDB_NOFLAGS); if (!mdb) { fprintf(stderr, "Could not open file\n"); exit(1); } if (argc - optind >= 2) { if (!mdb_set_default_backend(mdb, argv[optind + 1])) { fprintf(stderr, "Invalid backend type\n"); exit(1); } } /* read the catalog */ if (!mdb_read_catalog (mdb, MDB_TABLE)) { fprintf(stderr, "File does not appear to be an Access database\n"); exit(1); } mdb_print_schema(mdb, stdout, tabname, namespace, export_options); g_free(namespace); g_free(tabname); mdb_close (mdb); return 0; } mdbtools-0.7.1/src/util/mdb-sql.c000066400000000000000000000255451222645741400166330ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * 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. */ #include #ifdef HAVE_LIBREADLINE # if defined(HAVE_READLINE_READLINE_H) # include # elif defined(HAVE_READLINE_H) # include # else /* no readline.h */ extern char *readline (); # endif char *cmdline = NULL; #endif /* HAVE_LIBREADLINE */ #ifdef HAVE_READLINE_HISTORY # if defined(HAVE_READLINE_HISTORY_H) # include # elif defined(HAVE_HISTORY_H) # include # else /* no history.h */ extern void add_history (); extern int write_history (); extern int read_history (); extern void clear_history (); # endif #endif /* HAVE_READLINE_HISTORY */ #include #include "mdbsql.h" #ifdef DMALLOC #include "dmalloc.h" #endif void dump_results(FILE *out, MdbSQL *sql, char *delimiter); void dump_results_pp(FILE *out, MdbSQL *sql); #if SQL int headers = 1; int footers = 1; int pretty_print = 1; int showplan = 0; int noexec = 0; #ifdef HAVE_READLINE_HISTORY #define HISTFILE ".mdbhistory" #endif #ifndef HAVE_LIBREADLINE char *readline(char *prompt) { char *buf, line[1000]; int i = 0; puts(prompt); if (! fgets(line,1000,stdin)) { return NULL; } for (i=strlen(line);i>0;i--) { if (line[i]=='\n') { line[i]='\0'; break; } } buf = (char *) malloc(strlen(line)+1); strcpy(buf,line); return buf; } #endif static int strlen_utf(const char *s) { int len = 0; while (*s) { if ((*s++ & 0xc0) != 0x80) len++; } return len; } void do_set_cmd(MdbSQL *sql, char *s) { char *level1, *level2; level1 = strtok(s, " \t\n"); if (!level1) { printf("Usage: set [stats|showplan|noexec] [on|off]\n"); return; } if (!strcmp(level1,"stats")) { level2 = strtok(NULL, " \t"); if (!level2) { printf("Usage: set stats [on|off]\n"); return; } if (!strcmp(level2,"on")) { mdb_stats_on(sql->mdb); } else if (!strcmp(level2,"off")) { mdb_stats_off(sql->mdb); mdb_dump_stats(sql->mdb); } else { printf("Unknown stats option %s\n", level2); printf("Usage: set stats [on|off]\n"); } } else if (!strcmp(level1,"showplan")) { level2 = strtok(NULL, " \t"); if (!level2) { printf("Usage: set showplan [on|off]\n"); return; } if (!strcmp(level2,"on")) { showplan=1; } else if (!strcmp(level2,"off")) { showplan=0; } else { printf("Unknown showplan option %s\n", level2); printf("Usage: set showplan [on|off]\n"); } } else if (!strcmp(level1,"noexec")) { level2 = strtok(NULL, " \t"); if (!level2) { printf("Usage: set noexec [on|off]\n"); return; } if (!strcmp(level2,"on")) { noexec=1; } else if (!strcmp(level2,"off")) { noexec=0; } else { printf("Unknown noexec option %s\n", level2); printf("Usage: set noexec [on|off]\n"); } } else { printf("Unknown set command %s\n", level1); printf("Usage: set [stats|showplan|noexec] [on|off]\n"); } } int read_file(char *s, int line, unsigned int *bufsz, char *mybuf) { char *fname; FILE *in; char buf[256]; unsigned int cursz = 0; int lines = 0; fname = s; while (*fname && *fname==' ') fname++; if (! (in = fopen(fname, "r"))) { fprintf(stderr,"Unable to open file %s\n", fname); mybuf[0]=0; return 0; } while (fgets(buf, 255, in)) { cursz += strlen(buf) + 1; if (cursz > (*bufsz)) { (*bufsz) *= 2; mybuf = (char *) realloc(mybuf, *bufsz); } strcat(mybuf, buf); #ifdef HAVE_READLINE_HISTORY /* don't record blank lines */ if (strlen(buf)) add_history(buf); #endif strcat(mybuf, "\n"); lines++; printf("%d => %s",line+lines, buf); } return lines; } void run_query(FILE *out, MdbSQL *sql, char *mybuf, char *delimiter) { MdbTableDef *table; mdb_sql_run_query(sql, mybuf); if (!mdb_sql_has_error(sql)) { if (showplan) { table = sql->cur_table; if (table->sarg_tree) mdb_sql_dump_node(table->sarg_tree, 0); if (sql->cur_table->strategy == MDB_TABLE_SCAN) printf("Table scanning %s\n", table->name); else printf("Index scanning %s using %s\n", table->name, table->scan_idx->name); } if (noexec) { mdb_sql_reset(sql); return; } if (pretty_print) dump_results_pp(out, sql); else dump_results(out, sql, delimiter); } } void print_value(FILE *out, char *v, int sz, int first) { int i; int vlen; if (first) fputc('|', out); vlen = strlen_utf(v); fputs(v, out); for (i=vlen;inum_columns-1;j++) { sqlcol = g_ptr_array_index(sql->columns,j); fprintf(out, "%s%s", sqlcol->name, delimiter ? delimiter : "\t"); } sqlcol = g_ptr_array_index(sql->columns,sql->num_columns-1); fprintf(out, "%s", sqlcol->name); fprintf(out,"\n"); fflush(out); } while(mdb_fetch_row(sql->cur_table)) { row_count++; for (j=0;jnum_columns-1;j++) { sqlcol = g_ptr_array_index(sql->columns,j); fprintf(out, "%s%s", (char*)(sql->bound_values[j]), delimiter ? delimiter : "\t"); } sqlcol = g_ptr_array_index(sql->columns,sql->num_columns-1); fprintf(out, "%s", (char*)(sql->bound_values[sql->num_columns-1])); fprintf(out,"\n"); fflush(out); } if (footers) { print_rows_retrieved(out, row_count); } mdb_sql_reset(sql); } void dump_results_pp(FILE *out, MdbSQL *sql) { unsigned int j; MdbSQLColumn *sqlcol; unsigned long row_count = 0; /* print header */ if (headers) { for (j=0;jnum_columns;j++) { sqlcol = g_ptr_array_index(sql->columns,j); if (strlen(sqlcol->name)>sqlcol->disp_size) sqlcol->disp_size = strlen(sqlcol->name); print_break(out, sqlcol->disp_size, !j); } fprintf(out,"\n"); fflush(out); for (j=0;jnum_columns;j++) { sqlcol = g_ptr_array_index(sql->columns,j); print_value(out, sqlcol->name,sqlcol->disp_size,!j); } fprintf(out,"\n"); fflush(out); } for (j=0;jnum_columns;j++) { sqlcol = g_ptr_array_index(sql->columns,j); print_break(out, sqlcol->disp_size, !j); } fprintf(out,"\n"); fflush(out); /* print each row */ while(mdb_fetch_row(sql->cur_table)) { row_count++; for (j=0;jnum_columns;j++) { sqlcol = g_ptr_array_index(sql->columns,j); print_value(out, sql->bound_values[j],sqlcol->disp_size,!j); } fprintf(out,"\n"); fflush(out); } /* footer */ for (j=0;jnum_columns;j++) { sqlcol = g_ptr_array_index(sql->columns,j); print_break(out, sqlcol->disp_size, !j); } fprintf(out,"\n"); fflush(out); if (footers) { print_rows_retrieved(out, row_count); } /* clean up */ for (j=0;jnum_columns;j++) { g_free(sql->bound_values[j]); } mdb_sql_reset(sql); } int main(int argc, char **argv) { char *s = NULL; char prompt[20]; int line = 0; char *mybuf; unsigned int bufsz; MdbSQL *sql; int opt; FILE *in = NULL, *out = NULL; char *home = getenv("HOME"); char *histpath; char *delimiter = NULL; #ifdef HAVE_READLINE_HISTORY if (home) { histpath = (char *) g_strconcat(home, "/", HISTFILE, NULL); read_history(histpath); g_free(histpath); } #endif /* If input is coming from a pipe */ if (!isatty(fileno(stdin))) { in = stdin; } while ((opt=getopt(argc, argv, "HFpd:i:o:"))!=-1) { switch (opt) { case 'd': delimiter = (char *) g_strdup(optarg); break; case 'p': pretty_print=0; break; case 'H': headers=0; break; case 'F': footers=0; break; case 'i': if (!strcmp(optarg, "stdin")) in = stdin; else if (!(in = fopen(optarg, "r"))) { fprintf(stderr,"Unable to open file %s\n", optarg); exit(1); } break; case 'o': if (!(out = fopen(optarg, "w"))) { fprintf(stderr,"Unable to open file %s\n", optarg); exit(1); } break; default: fprintf(stdout,"Unknown option.\nUsage: %s [-HFp] [-d ] [-i ] [-o ] []\n", argv[0]); exit(1); } } /* initialize the SQL engine */ sql = mdb_sql_init(); if (argc>optind) { mdb_sql_open(sql, argv[optind]); } /* give the buffer an initial size */ bufsz = 4096; mybuf = (char *) g_malloc(bufsz); mybuf[0]='\0'; while (1) { line ++; if (s) free(s); if (in) { s=malloc(256); if ((!s) || (!fgets(s, 256, in))) { /* if we have something in the buffer, run it */ if (strlen(mybuf)) run_query((out) ? out : stdout, sql, mybuf, delimiter); break; } if (s[strlen(s)-1]=='\n') s[strlen(s)-1]=0; } else { sprintf(prompt, "%d => ", line); s=readline(prompt); if (!s) break; } if (!strcmp(s,"exit") || !strcmp(s,"quit") || !strcmp(s,"bye")) break; if (line==1 && (!strncmp(s,"set ",4) || !strcmp(s,"set"))) { do_set_cmd(sql, &s[3]); line = 0; } else if (!strcmp(s,"go")) { line = 0; run_query((out) ? out : stdout, sql, mybuf, delimiter); mybuf[0]='\0'; } else if (!strcmp(s,"reset")) { line = 0; mybuf[0]='\0'; } else if (!strncmp(s,":r",2)) { line += read_file(&s[2], line, &bufsz, mybuf); } else { while (strlen(mybuf) + strlen(s) > bufsz) { bufsz *= 2; mybuf = (char *) g_realloc(mybuf, bufsz); } #ifdef HAVE_READLINE_HISTORY /* don't record blank lines */ if (strlen(s)) add_history(s); #endif strcat(mybuf,s); /* preserve line numbering for the parser */ strcat(mybuf,"\n"); } } mdb_sql_exit(sql); g_free(mybuf); g_free(delimiter); if (s) free(s); if (out) fclose(out); if ((in) && (in != stdin)) fclose(in); #ifdef HAVE_READLINE_HISTORY if (home) { histpath = (char *) g_strconcat(home, "/", HISTFILE, NULL); write_history(histpath); g_free(histpath); clear_history(); } #endif return 0; } #else int main(int argc, char **argv) { fprintf(stderr,"You must configure using --enable-sql to get SQL support\n"); return -1; } #endif mdbtools-0.7.1/src/util/mdb-tables.c000066400000000000000000000073231222645741400173000ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * 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. */ /* this utility dumps the schema for an existing database */ #include "mdbtools.h" #ifdef DMALLOC #include "dmalloc.h" #endif struct type_struct { char *name; int value; } types[] = { { "form", MDB_FORM }, { "table", MDB_TABLE }, { "macro", MDB_MACRO }, { "systable", MDB_SYSTEM_TABLE }, { "report", MDB_REPORT }, { "query", MDB_QUERY }, { "linkedtable", MDB_LINKED_TABLE }, { "module", MDB_MODULE }, { "relationship", MDB_RELATIONSHIP }, { "dbprop", MDB_DATABASE_PROPERTY }, { "any", MDB_ANY }, { "all", MDB_ANY }, { NULL, 0 } }; char * valid_types() { static char ret[256]; /* be sure to allow for enough space if adding more */ int i = 0; ret[0] = '\0'; while (types[i].name) { strcat(ret, types[i].name); strcat(ret, " "); i++; } return ret; } int get_obj_type(char *typename, int *ret) { int i=0; int found=0; char *s = typename; while (*s) { *s=tolower(*s); s++; } while (types[i].name) { if (!strcmp(types[i].name, typename)) { found=1; *ret = types[i].value; } i++; } return found; } int main (int argc, char **argv) { unsigned int i; MdbHandle *mdb; MdbCatalogEntry *entry; char *delimiter = NULL; int line_break=0; int skip_sys=1; int show_type=0; int opt; int objtype = MDB_TABLE; if (argc < 2) { fprintf (stderr, "Usage: %s [-S] [-1 | -d] [-t ] [-T] \n",argv[0]); fprintf (stderr, " Valid types are: %s\n",valid_types()); exit (1); } while ((opt=getopt(argc, argv, "S1Td:t:"))!=-1) { switch (opt) { case 'S': skip_sys = 0; break; case 'T': show_type = 1; break; case '1': line_break = 1; break; case 't': if (!get_obj_type(optarg, &objtype)) { fprintf(stderr,"Invalid type name.\n"); fprintf (stderr, "Valid types are: %s\n",valid_types()); exit(1); } break; case 'd': delimiter = (char *) g_strdup(optarg); break; } } /* open the database */ if (!(mdb = mdb_open (argv[optind], MDB_NOFLAGS))) { fprintf(stderr,"Couldn't open database.\n"); exit(1); } /* read the catalog */ if (!mdb_read_catalog (mdb, MDB_ANY)) { fprintf(stderr,"File does not appear to be an Access database\n"); exit(1); } /* loop over each entry in the catalog */ for (i=0; i < mdb->num_catalog; i++) { entry = g_ptr_array_index (mdb->catalog, i); if (entry->object_type != objtype && objtype!=MDB_ANY) continue; if (skip_sys && mdb_is_system_table(entry)) continue; if (show_type) { if (delimiter) puts(delimiter); printf("%d ", entry->object_type); } if (line_break) printf ("%s\n", entry->object_name); else if (delimiter) printf ("%s%s", entry->object_name, delimiter); else printf ("%s ", entry->object_name); } if (!line_break) fprintf (stdout, "\n"); mdb_close(mdb); g_free(delimiter); return 0; } mdbtools-0.7.1/src/util/mdb-ver.c000066400000000000000000000037751222645741400166310ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000-2004 Brian Bruns * * 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. */ #include #include "mdbtools.h" #include "mdbver.h" #include "mdbprivate.h" #ifdef DMALLOC #include "dmalloc.h" #endif int main(int argc, char **argv) { MdbHandle *mdb; int print_mdbver = 0; int opt; /* setlocale (LC_ALL, ""); */ bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); while ((opt=getopt(argc, argv, "M"))!=-1) { switch (opt) { case 'M': print_mdbver = 1; break; default: break; } } if (print_mdbver) { fprintf(stdout,"%s\n", MDB_FULL_VERSION); if (argc-optind < 1) exit(0); } /* ** optind is now the position of the first non-option arg, ** see getopt(3) */ if (argc-optind < 1) { fprintf(stderr,_("Usage: %s [-M] \n"),argv[0]); exit(1); } if (!(mdb = mdb_open(argv[optind], MDB_NOFLAGS))) { fprintf(stderr,_("Error: unable to open file %s\n"),argv[optind]); exit(1); } switch(mdb->f->jet_version) { case MDB_VER_JET3: printf("JET3\n"); break; case MDB_VER_JET4: printf("JET4\n"); break; case MDB_VER_ACCDB_2007: printf("ACE12\n"); break; case MDB_VER_ACCDB_2010: printf("ACE14\n"); break; default: printf(_("unknown database version\n")); break; } mdb_close(mdb); return 0; } mdbtools-0.7.1/src/util/prcat.c000066400000000000000000000022371222645741400163760ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * 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. */ #include "mdbtools.h" int main(int argc, char **argv) { MdbHandle *mdb; if (argc<2 || argc>3) { fprintf(stderr, "Usage: %s []\n", argv[0]); fprintf(stderr, "Use objtype -1 for all\n"); exit(1); } mdb = mdb_open(argv[1], MDB_NOFLAGS); mdb_dump_catalog(mdb,(argc > 2) ? atoi(argv[2]) : MDB_TABLE); mdb_close(mdb); return 0; } mdbtools-0.7.1/src/util/prdata.c000066400000000000000000000023161222645741400165360ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * 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. */ #include "mdbtools.h" int main(int argc, char **argv) { MdbHandle *mdb; MdbTableDef *table; if (argc<2) { fprintf(stderr,"Usage: %s
    \n",argv[0]); exit(1); } mdb = mdb_open(argv[1], MDB_NOFLAGS); table = mdb_read_table_by_name(mdb, argv[2], MDB_TABLE); if (table) { mdb_read_columns(table); mdb_data_dump(table); mdb_free_tabledef(table); } mdb_close(mdb); return 0; } mdbtools-0.7.1/src/util/prdump.c000066400000000000000000000025421222645741400165730ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * 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. */ #include "mdbtools.h" int main(int argc, char **argv) { MdbHandle *mdb; int j; int page, start, stop; if (argc<4) { fprintf(stderr,"Usage: %s \n",argv[0]); exit(1); } mdb = mdb_open(argv[1], MDB_NOFLAGS); mdb_read_catalog(mdb, MDB_TABLE); sscanf (argv [2], "%d", &page); sscanf (argv [3], "%d", &start); sscanf (argv [4], "%d", &stop); mdb_read_pg (mdb, page); for (j = start; j < stop; j++) { fprintf (stderr, "%4x %4x %c\n", j, mdb->pg_buf [j], mdb->pg_buf [j]); } mdb_close(mdb); return 0; } mdbtools-0.7.1/src/util/prfreemap.c000066400000000000000000000030321222645741400172400ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * 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. */ #include "mdbtools.h" int main(int argc, char **argv) { MdbHandle *mdb; int j; long int pgnum = 0, row_start; size_t map_sz; int coln = 1; unsigned char *map_buf; if (argc<2) { fprintf(stderr,"Usage: %s \n",argv[0]); exit(1); } mdb = mdb_open(argv[1], MDB_NOFLAGS); mdb_read_pg (mdb, 1); mdb_find_row(mdb, 0, &row_start, &map_sz); map_buf = &mdb->pg_buf[row_start]; map_sz --; /* * trim the end of a type 0 map */ if (map_buf[0]==0) while (map_buf[map_sz]==0xff) map_sz--; while ((pgnum = mdb_map_find_next(mdb, map_buf, map_sz, pgnum))>0) { printf("%6lu ",(long unsigned) pgnum); if (coln==10) { printf("\n"); coln = 0; } coln++; } if (coln!=1) printf("\n"); mdb_close(mdb); return 0; } mdbtools-0.7.1/src/util/prindex.c000066400000000000000000000075621222645741400167440ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * 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. */ #include "mdbtools.h" extern char idx_to_text[]; void walk_index(MdbHandle *mdb, MdbIndex *idx); int main(int argc, char **argv) { unsigned int j; MdbHandle *mdb; MdbTableDef *table; MdbIndex *idx; if (argc<4) { fprintf(stderr,"Usage: %s
    \n",argv[0]); exit(1); } if (!(mdb = mdb_open(argv[1], MDB_NOFLAGS))) { fprintf(stderr,"Unable to open database.\n"); exit(1); } table = mdb_read_table_by_name(mdb, argv[2], MDB_TABLE); if (table) { mdb_read_columns(table); mdb_read_indices(table); for (j=0;jnum_idxs;j++) { idx = g_ptr_array_index (table->indices, j); if (!strcmp(idx->name, argv[3])) { walk_index(mdb, idx); } } mdb_free_tabledef(table); } else { fprintf(stderr,"No table named %s found.\n", argv[2]); } mdb_close(mdb); return 0; } char * page_name(int page_type) { switch(page_type) { case 0x00: return "Database Properties"; break; case 0x01: return "Data"; break; case 0x02: return "Table Definition"; break; case 0x03: return "Index"; break; case 0x04: return "Index Leaf"; break; case 0x05: return "Page Usage"; break; default: return "Unknown"; } } void check_row(MdbHandle *mdb, MdbIndex *idx, guint32 pg, int row) { MdbField fields[256]; unsigned int num_fields, i, j; int row_start; size_t row_size; MdbColumn *col; gchar buf[256], key[256]; int elem; MdbTableDef *table = idx->table; mdb_read_pg(mdb, pg); mdb_find_row(mdb, row, &row_start, &row_size); num_fields = mdb_crack_row(table, row_start, row_start + row_size - 1, fields); for (i=0;inum_keys;i++) { col=g_ptr_array_index(table->columns,idx->key_col_num[i]-1); if (col->col_type==MDB_TEXT) { mdb_index_hash_text(buf, key); } for (j=0;jkey_col_num[i]) { elem = j; break; } } if (j==num_fields) { fprintf(stderr, "ERROR Lost field #%d\n", idx->key_col_num[i]); continue; } //j = idx->key_col_num[i]; strncpy(buf, fields[elem].value, fields[elem].siz); buf[fields[elem].siz]=0; //fprintf(stdout, "elem %d %d column %d %s %s\n",elem, fields[elem].colnum, idx->key_col_num[i], col->name, buf); if (col->col_type == MDB_TEXT) { // fprintf(stdout, "%s = %s \n", buf, key); } } } void walk_index(MdbHandle *mdb, MdbIndex *idx) { guint32 pg; guint16 row; MdbHandle *mdbidx; MdbIndexChain chain; #if 0 MdbTableDef *table = idx->table; MdbSarg sarg; sarg.op = MDB_EQUAL; //strcpy(sarg.value.s, "SP"); sarg.value.i = 2; mdb_add_sarg_by_name(table, "ShipperID", &sarg); #endif memset(&chain, 0, sizeof(MdbIndexChain)); printf("name %s\n", idx->name); printf("root page %lu\n", (long unsigned) idx->first_pg); /* clone the handle to search the index, and use the original to read * the data */ mdbidx = mdb_clone_handle(mdb); mdb_read_pg(mdbidx, idx->first_pg); //printf("page type %02x %s\n", mdbidx->pg_buf[0], page_name(mdbidx->pg_buf[0])); while (mdb_index_find_next(mdbidx, idx, &chain, &pg, &row)) { printf("row = %d pg = %lu\n", row, (long unsigned) pg); check_row(mdb, idx, pg, row); } mdb_close(mdbidx); } mdbtools-0.7.1/src/util/prkkd.c000066400000000000000000000024431222645741400163770ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * 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. */ #include "mdbtools.h" int main(int argc, char **argv) { #if 0 MdbHandle *mdb; MdbTableDef *table; if (argc<3) { fprintf(stderr,"Usage: %s
    \n",argv[0]); exit(1); } mdb = mdb_open(argv[1], MDB_NOFLAGS); table = mdb_read_table_by_name(mdb, argv[2], MDB_TABLE); if (!table) { fprintf(stderr,"No table named %s found.\n", argv[2]); exit(1); } /* FIXME: table->entry->*kkd* are not initialized */ mdb_kkd_dump(table->entry); mdb_close(mdb); #endif return 0; } mdbtools-0.7.1/src/util/prole.c000066400000000000000000000043051222645741400164040ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * 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. */ #include "mdbtools.h" void dump_ole(MdbTableDef *table, char *colname, char *sargname); int main(int argc, char **argv) { MdbHandle *mdb; MdbTableDef *table; char *dot, *colname, *tabname; char *sargname = NULL; if (argc<2) { fprintf(stderr,"Usage: %s [sargs]\n",argv[0]); exit(1); } mdb = mdb_open(argv[1], MDB_NOFLAGS); dot = strchr(argv[2],'.'); if (argc>3) sargname = argv[3]; if (!dot) { fprintf(stderr,"Usage: %s [sarg]\n",argv[0]); exit(1); } tabname = argv[2]; *dot='\0'; colname = ++dot; table = mdb_read_table_by_name(mdb, tabname, MDB_TABLE); if (table) { mdb_read_columns(table); dump_ole(table, colname, sargname); mdb_free_tabledef(table); } mdb_close(mdb); return 0; } void dump_ole(MdbTableDef *table, char *colname, char *sargname) { char ole_data[200000]; int len; MdbSarg sarg; char *sargcol, *sargop, *sargval; mdb_bind_column_by_name(table, colname, ole_data, &len); if (sargname) { sargcol = strtok(sargname," "); sargop = strtok(NULL," "); sargval = strtok(NULL," "); printf("col %s op %s val %s\n",sargcol,sargop,sargval); sarg.op = MDB_EQUAL; /* only support = for now, sorry */ strcpy(sarg.value.s, sargval); mdb_add_sarg_by_name(table, sargcol, &sarg); } mdb_rewind_table(table); while (mdb_fetch_row(table)) { mdb_buffer_dump(ole_data, 0, len); printf("---\n"); } } mdbtools-0.7.1/src/util/prtable.c000066400000000000000000000026271222645741400167210ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * 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. */ #include "mdbtools.h" int main(int argc, char **argv) { unsigned int i; MdbHandle *mdb; MdbCatalogEntry *entry; int found = 0; if (argc<3) { fprintf(stderr,"Usage: %s
    \n",argv[0]); exit(1); } mdb = mdb_open(argv[1], MDB_NOFLAGS); mdb_read_catalog(mdb, MDB_TABLE); for (i=0;inum_catalog;i++) { entry = g_ptr_array_index(mdb->catalog,i); if (entry->object_type == MDB_TABLE && !strcmp(entry->object_name,argv[2])) { mdb_table_dump(entry); found++; } } if (!found) { fprintf(stderr,"No table named %s found.\n", argv[2]); } mdb_close(mdb); return 0; } mdbtools-0.7.1/src/util/sargtest.c000066400000000000000000000044531222645741400171230ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * 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. */ #include "mdbtools.h" #define TABLE_NAME "Orders" #define MDB_FILE "Northwind.mdb" #define DELIMETER "\t" void print_table(MdbTableDef *table); main(int argc, char **argv) { MdbHandle *mdb; MdbTableDef *table; if (!(mdb = mdb_open(MDB_FILE, MDB_NOFLAGS))) { exit(1); } table = mdb_read_table_by_name(mdb, TABLE_NAME, MDB_TABLE); if (table) { print_table(table); mdb_free_tabledef(table); } mdb_close(mdb); return 0; } void print_table(MdbTableDef *table) { int j; /* doesn't handle tables > 256 columns. Can that happen? */ char *bound_values[256]; MdbColumn *col; MdbSarg sarg; mdb_read_columns(table); sarg.op = MDB_EQUAL; // sarg.value.i = 11070; strcpy(sarg.value.s, "Reggiani Caseifici"); mdb_add_sarg_by_name(table, "ShipName", &sarg); mdb_rewind_table(table); for (j=0;jnum_cols;j++) { bound_values[j] = (char *) g_malloc(MDB_BIND_SIZE); bound_values[j][0] = '\0'; mdb_bind_column(table, j+1, bound_values[j], NULL); } /* print header */ col=g_ptr_array_index(table->columns,0); fprintf(stdout,"%s",col->name); for (j=1;jnum_cols;j++) { col=g_ptr_array_index(table->columns,j); fprintf(stdout,"%s%s",DELIMETER,col->name); } fprintf(stdout,"\n"); /* print each row */ while(mdb_fetch_row(table)) { fprintf(stdout,"%s",bound_values[0]); for (j=1;jnum_cols;j++) { fprintf(stdout,"%s%s",DELIMETER,bound_values[j]); } fprintf(stdout,"\n"); } /* clean up */ for (j=0;jnum_cols;j++) { g_free(bound_values[j]); } } mdbtools-0.7.1/src/util/updrow.c000066400000000000000000000052171222645741400166060ustar00rootroot00000000000000/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * 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. */ #include "mdbtools.h" void read_to_row(MdbTableDef *table, char *sargname); int main(int argc, char **argv) { MdbHandle *mdb; MdbTableDef *table; char *colname, *tabname; char *colval; int colnum; char *sargname = NULL; char *updstr = NULL; char data[255]; int len; if (argc<4) { fprintf(stderr,"Usage: %s
    \n",argv[0]); exit(1); } mdb = mdb_open(argv[1], MDB_WRITABLE); tabname = argv[2]; sargname = argv[3]; updstr = strdup(argv[4]); table = mdb_read_table_by_name(mdb, tabname, MDB_TABLE); if (table) { mdb_read_columns(table); mdb_read_indices(table); printf("updstr %s\n",updstr); colname = strtok(updstr,"="); colval = strtok(NULL,"="); colnum = mdb_bind_column_by_name(table, colname, data, &len); printf("column %d\n", colnum); read_to_row(table, sargname); printf("current value of %s is %s, changing to %s\n", colname, data, colval); len = strlen(colval); strcpy(data,colval); mdb_update_row(table); mdb_free_tabledef(table); } mdb_close(mdb); return 0; } void read_to_row(MdbTableDef *table, char *sargname) { static MdbSargNode sarg; char *sargcol, *sargop, *sargval; unsigned int i; MdbColumn *col; if (sargname) { sargcol = strtok(sargname," "); for (i=0;inum_cols;i++) { col=g_ptr_array_index(table->columns,i); if (!strcasecmp(col->name, (char *)sargcol)) { sarg.col = col; break; } } sargop = strtok(NULL," "); sargval = strtok(NULL," "); printf("col %s op %s val %s\n",sargcol,sargop,sargval); sarg.op = MDB_EQUAL; /* only support = for now, sorry */ sarg.value.i = atoi(sargval); table->sarg_tree = &sarg; // mdb_add_sarg_by_name(table, sargcol, &sarg); } mdb_rewind_table(table); while (mdb_fetch_row(table)) { printf("row found at page %d row %d\n", table->cur_phys_pg, table->cur_row); return; } } mdbtools-0.7.1/xmldocs.make000066400000000000000000000061541222645741400156670ustar00rootroot00000000000000# # No modifications of this Makefile should be necessary. # # To use this template: # 1) Define: figdir, docname, lang, omffile, and entities in # your Makefile.am file for each document directory, # although figdir, omffile, and entities may be empty # 2) Make sure the Makefile in (1) also includes # "include $(top_srcdir)/xmldocs.make" and # "dist-hook: app-dist-hook". # 3) Optionally define 'entities' to hold xml entities which # you would also like installed # 4) Figures must go under $(figdir)/ and be in PNG format # 5) You should only have one document per directory # 6) Note that the figure directory, $(figdir)/, should not have its # own Makefile since this Makefile installs those figures. # # example Makefile.am: # figdir = figures # docname = scrollkeeper-manual # lang = C # omffile=scrollkeeper-manual-C.omf # entities = fdl.xml # include $(top_srcdir)/xmldocs.make # dist-hook: app-dist-hook # # About this file: # This file was taken from scrollkeeper_example2, a package illustrating # how to install documentation and OMF files for use with ScrollKeeper # 0.3.x and 0.4.x. For more information, see: # http://scrollkeeper.sourceforge.net/ # Version: 0.1.2 (last updated: March 20, 2002) # # ********** Begin of section some packagers may need to modify ********** # This variable (docdir) specifies where the documents should be installed. # This default value should work for most packages. docdir = $(datadir)/gnome/help/$(docname)/$(lang) # ********** You should not have to edit below this line ********** xml_files = $(entities) $(docname).xml EXTRA_DIST = $(xml_files) $(omffile) CLEANFILES = omf_timestamp include $(top_srcdir)/omf.make all: omf $(docname).xml: $(entities) -ourdir=`pwd`; \ cd $(srcdir); \ cp $(entities) $$ourdir app-dist-hook: if test "$(figdir)"; then \ $(mkinstalldirs) $(distdir)/$(figdir); \ for file in $(srcdir)/$(figdir)/*.png; do \ basefile=`echo $$file | sed -e 's,^.*/,,'`; \ $(INSTALL_DATA) $$file $(distdir)/$(figdir)/$$basefile; \ done \ fi install-data-local: omf $(mkinstalldirs) $(DESTDIR)$(docdir) for file in $(xml_files); do \ cp $(srcdir)/$$file $(DESTDIR)$(docdir); \ done if test "$(figdir)"; then \ $(mkinstalldirs) $(DESTDIR)$(docdir)/$(figdir); \ for file in $(srcdir)/$(figdir)/*.png; do \ basefile=`echo $$file | sed -e 's,^.*/,,'`; \ $(INSTALL_DATA) $$file $(DESTDIR)$(docdir)/$(figdir)/$$basefile; \ done \ fi install-data-hook: install-data-hook-omf uninstall-local: uninstall-local-doc uninstall-local-omf uninstall-local-doc: -if test "$(figdir)"; then \ for file in $(srcdir)/$(figdir)/*.png; do \ basefile=`echo $$file | sed -e 's,^.*/,,'`; \ rm -f $(DESTDIR)$(docdir)/$(figdir)/$$basefile; \ done; \ rmdir $(DESTDIR)$(docdir)/$(figdir); \ fi -for file in $(xml_files); do \ rm -f $(DESTDIR)$(docdir)/$$file; \ done -rmdir $(DESTDIR)$(docdir) clean-local: clean-local-doc clean-local-omf # for non-srcdir builds, remove the copied entities. clean-local-doc: if test $(srcdir) != .; then \ rm -f $(entities); \ fi