pax_global_header00006660000000000000000000000064137406007220014513gustar00rootroot0000000000000052 comment=2270ba7e825eeab771ff45e77ba137fe80862410 bless-0.6.3/000077500000000000000000000000001374060072200126315ustar00rootroot00000000000000bless-0.6.3/.github/000077500000000000000000000000001374060072200141715ustar00rootroot00000000000000bless-0.6.3/.github/workflows/000077500000000000000000000000001374060072200162265ustar00rootroot00000000000000bless-0.6.3/.github/workflows/build.yml000066400000000000000000000011021374060072200200420ustar00rootroot00000000000000name: build on: push: branches: - master pull_request: branches: - master jobs: build: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v1 - name: Install dependencies run: > sudo apt-get install meson mono-devel libgtk2.0-cil-dev libnunit-cil-dev nunit-console xsltproc docbook-xsl - name: Setup run: meson setup build - name: Build run: ninja -C build - name: Run tests run: meson test -v -C build - name: Install run: DESTDIR=/tmp/bless-install ninja -C build install bless-0.6.3/.gitignore000066400000000000000000000000651374060072200146220ustar00rootroot00000000000000**/*~ po/** !po/LINGUAS !po/Makevars !po/POTFILES.in bless-0.6.3/AUTHORS000066400000000000000000000016301374060072200137010ustar00rootroot00000000000000Main development team ===================== * Alexandros Frantzis Contributors ============ Many thanks to: * Jeremy Messenger Bug fixes, FreeBSD port * Ioannis Ramfos Bug hunting (QA), Bug fixes * Michael Iatrou Bless logo in About Dialog. * Mike Hearn Code patches * Mirco "MacSlow" Müller RPM packaging and .spec file * Thomas Liebetraut Exceptional bug hunting and fixes * Saleem Abdulrasool Support for DESTDIR in Makefiles * Mike Auty Bug fixes * Marek Cernocký Czech translation and i18n related bug fixes. ... if I have forgotten someone please remind me! bless-0.6.3/COPYING000066400000000000000000000431311374060072200136660ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library General Public License instead of this License. bless-0.6.3/NEWS000066400000000000000000000145731374060072200133420ustar00rootroot00000000000000Bless v0.6.3 20201011 --------------------- * Add plugin to allow copying the current offset to clipboard (gh #15). * Fix display of Courier font glyphs (gh #25). * Use Gtk.Builder for UI loading, drop libglade (gh #2). * Move to the meson build system, drop autotools. * Fix crash when plugins directory path is a file (gh #32). * Add binary+ASCII layout file (gh #23). * Fix issue with statusbar not showing all information (gh #14). Bless v0.6.2 20190418 --------------------- * Fix rendering with monospace fonts with ligatures (gh #1). * Fix crash when searching (gh #3). * Fix incorrect notifications for file content changes (gh #7). * Fix crash when trying to save a file in-place. * Fix (harmless) Gtk-CRITICAL errors for file content change notifications. * Fix installation with newer autotools (gh #8). Bless v0.6.1 20180919 - Better late than never ---------------------------------------------- * Use 'mcs' compiler by default, and allow proper overriding during configure. * Fix problem saving when the tempdir config entry hasn't been specified. * Fix reading and writing to XML config files. * Fix crash when trying to save a file without write permissions. * Fix various compilation warnings. * Moved to new home: https://github.com/afrantzis/bless Bless v0.6.0 20080814 --------------------- * Read/Write support for block devices. * Saving speed improvements. * Rendering speed improvements. * Various bug fixes (gna.org #9660, #10378, #11397, #10601) * A lot of internal changes that pave the way for exciting features... Bless v0.5.2 20070831 --------------------- * Pluginified Areas subsystem. * Bless is now installed in a more standard location. * Various bug fixes (gna.org #9313, #9543, #9664, #9659) Bless v0.5.1 20070602 --------------------- * New Select All action. * Plugin to perform bitwise operations on data. * Added right-click popup menus. * Workaround for Mono 1.1.x bug that caused incomplete gui (gna.org #8975) * Various bug fixes (gna.org #8916, #9084, #9094) Bless v0.5.0 20070330 --------------------- * Brand new plugin architecture (GUI and export). * Export functionality (text and html, others with plugins). * Reduced memory usage. * Fixed garbled display issue (thanks to Thomas Liebetraut). * Localization support. * New ways to select data ranges. Bless v0.4.1 20060803 --------------------- * Fixed compilation problems with newer versions of Mono. * Added a work-around for the long standing garbled display issue (See README). Bless v0.4.0 20051009 --------------------- * Upgraded widgets to Gtk# 2 (Gtk+ 2.4). * Added a toolbar. * Added highlighting of patterns matching the current selection. * Added the ability to open files by dragging and dropping them into Bless. * Improved build system (for packagers). * Many bugfixes and usability improvements. Bless v0.3.6.1 20050827 ----------------------- * Fixed build system problems Bless v0.3.6 20050725 --------------------- * Added Preferences (undo limit, session loading options, default layout etc) * Added the ability to change the statusbar information (offset, selection) number base by clicking on it. * Reduced memory consumption for heavily modified files. * Improved Find/Replace and Goto Offset UI (bars instead of dialogs). * Misc usability improvements. Bless v0.3.5 20050519 --------------------- This is mainly a bugfix release * Fixed crash when saving a new file in 0.3.4. * Fixed subtle Gtk+ threading problems. * Made save as operation more robust. * Fixed problem with Notebook arrows. * Fixed dialog focusing problems. * Fixed crash with find/replace. * New tag in layout files, allows you to set the number of bytes each offset in the offset area will have. * You can now change the edit mode by clicking on the OVR/INS statusbar. Bless v0.3.4 20050509 --------------------- * Added recent file support. * Added session support (Bless saves its state when you quit and tries to reload it when you start). * Reduced memory consumption by sharing common resources. * Added notification when a file changes outside Bless. * Better help integration with scrollkeeper and GNOME. * Changed user configuration directory to adhere to XDG specification (usually $HOME/.config/bless). Bless v0.3.3 20050412 --------------------- * Added full copy/paste support. * Increased speed and gui responsiveness by moving find/replace and save operations in separate threads. * Added new docbook manual. * Changed build system to use autotools. * When installing, an entry is added to the menu of freedesktop compliant desktop enviroments (eg GNOME). Bless v0.3.2 20050311 --------------------- * Increased search speed by using a boyer-moore based algorithm. * Greatly improved performance of replace all operation. * Added a Conversion Table (converts the data at the cursor to various formats). * Find and Replace dialogs can now parse numbers in all major bases. * New tag in layout files allows setting the bytes per row of an area to a fixed value. * The default values of some colors (eg selection) are now set from the theme. * Fixed compilation errors/warnings with Mono 1.1.4 and removed the dependency of the main program on the NUnit framework. Bless v0.3.1 20050214 --------------------- * Added replace functionality. * Find and Replace dialogs get their search pattern from the current selection. * You can now revert a file to its previous saved state. * Added Backspace key support for deletion. * Improved statusbar handling (View->Statusbar). Bless v0.3.0 20050205 --------------------- * Bless now features multiple tabs! * Added support for finding bytes in hexadecimal and text. * You can go to a specified offset within the file. * Reduced memory usage. * Improved UI, especially when confirming file saves. Bless v0.2.3 20041213 --------------------- * Support for inserting bytes. * Saving files is much quicker now. * Undo/redo behaviour has been improved. * A progress dialog is shown if a save lasts for more than 1 second. * The window title is marked with an asterisk if the file has been modified. Bless v0.2.2 20041127 --------------------- This release contains many bug fixes and enhancements. The most important ones are: * mouse wheel scrolling * improved memory handling (smaller footprint) * ability to create new files/append to existing ones * proper mouse and keyboard selection behaviour * more robust handling of files bless-0.6.3/README000066400000000000000000000123421374060072200135130ustar00rootroot00000000000000Bless - Gtk# Hex Editor v0.6.3 ============================== Copyright (c) 2004-2020, Alexandros Frantzis Thank you for using ( or at least trying out :) ) Bless! Contents 1. Description 2. Project Web Site and contact info 3. Requirements 4. Installation 5. Running 6. Documentation 7. Known Issues -------------- 1. Description -------------- Bless is a binary (hex) editor, a program that enables you to edit files as a sequence of bytes. It is written in C# and uses the Gtk# bindings for the GTK+ toolkit. Bless is distributed under the terms of the GNU General Public License (GPL-2.0-or-later). See the file COPYING for more information. Main Features ------------- * Efficient editing of large data files. * Raw disk editing. * Multilevel undo - redo operations. * Customizable data views. * Fast data rendering on screen. * Multiple Tabs. * Fast Find and Replace operations. * Conversion Table. * Advanced Copy/Paste capabilities. * Multi-threaded search and save operations. * Export to text and html (others with plugins). * Extensibility with Plugins. Planned Features ---------------- * Scripting language for binary file manipulation. ------------------------------------ 2. Project Web Site and contact info ------------------------------------ More information, bug reports and the latest releases can be found at: https://github.com/afrantzis/bless I can be contacted at: alf82 [at] freemail [dot] gr. --------------- 3. Requirements --------------- The main target platform for bless is GNU/Linux. However, all the libraries it uses are cross-platform, so bless should be able to run without problems on all the major platforms (GNU/Linux, *BSD, Solaris, Win32). To build and run the current version of bless you need: * GTK+ >= 2.8.x (Included in all modern GNU/Linux distributions, http://www.gtk.org) * mono/.NET runtime and C# compiler >= 1.1.14 (http://www.mono-project.com) * Gtk# bindings >= 2.8 for GTK+ (http://gtk-sharp.sourceforge.net) * pkg-config (Included in all modern GNU/Linux distributions) * meson >= 0.46 * nunit and nunit-console, if you want to build and run tests * xsltproc and docbook stylesheet, if you want to produce HTML documentation Development is done using the latest stable versions of the above libraries. Although using an older version may be OK, there is no guarantee that there will not be problems. --------------- 4. Installation --------------- Quick: git clone https://github.com/afrantzis/bless meson setup build (-Dopt=val --buildtype=type ...) ninja -C build (ninja -C build install) Detailed: Step 1: Get the source --------------------------------- To get the latest source: git clone https://github.com/afrantzis/bless For a compressed tarball use: tar -xf bless-a.b.c.tar.gz Step 2: Configure the build ----------------------------- Enter the directory created in the previous step (bless or bless-a.b.c). To configure the build and check that your system has all the required libraries use: $ meson setup build (-Dopt=val --buildtype=type ...) Use the "-Dprefix=PREFIX" option to set the installation directory prefix. By default the prefix is '/usr/local'. You can use the "--buildtype=release" option to build bless in release mode, by default the debug mode is built. Step 3: Build the program ----------------------------- Type 'ninja -C build'. This will create 'bless.exe' and the necessary library files in the build/src directory. You can also type 'ninja -C build test' to run some tests on various bless components. Note that running the tests requires the 'nunit-console' binary. Step 4: Install the program (optional) -------------------------------------- Become root and type 'ninja -C build install'. ---------- 5. Running ---------- If you chose to install the program, just type 'bless'. In any case you can run the program by typing 'mono build/src/bless.exe' from within the top source directory. Enjoy! ---------------- 6. Documentation ---------------- The doc/ directory contains documentation directed both at the user and at the developer who wants to explore Bless. The doc/user/ subdirectory contains information about using bless whereas doc/developer/ contains developer information (bless api etc). Note: The developer documentation is almost non-existent. --------------- 7. Known Issues --------------- * To be able to save a file under the same name (File->Save command) you need to have (temporarily) enough disk space to hold both the original and the new file. This happens because the new file is created in the /tmp directory and then moved to its proper position. For example if you have a 20MB file and edit it so that it becomes 21MB and the new file is supposed to be saved in the same storage device as /tmp, you need to have 20+21=41MB free space in that storage device to be able to save it. After a successful save, the original file is deleted, in this case freeing 20MB. Although this can be a problem (when there is not enough disk space), it can also be seen as a safety measure in case something goes wrong when saving. A notable exception to the above is when the size of the file to be saved has not been changed. In that case the file is saved in-place. bless-0.6.3/README.packaging000066400000000000000000000006271374060072200154410ustar00rootroot00000000000000Bless - Gtk# Hex Editor Packaging Notes ======================================= This document is aimed at people trying to package Bless for a specific distribution. Bless can easily be packaged using the following method: meson setup build -Dprefix=/usr ninja -C build DESTDIR=/tmp-pkg-path ninja -C build install The contents of the /tmp-pkg-path can then be compressed and distributed as a package. bless-0.6.3/bless.mdp000066400000000000000000000305431374060072200144500ustar00rootroot00000000000000 bless-0.6.3/bless.mds000066400000000000000000000010731374060072200144470ustar00rootroot00000000000000 bless-0.6.3/data/000077500000000000000000000000001374060072200135425ustar00rootroot00000000000000bless-0.6.3/data/README.bless-courier000066400000000000000000000011761374060072200172040ustar00rootroot00000000000000bless-courier.ttf is a ttf version of the IBM Courier font as shipped by texlive at: https://www.tug.org/texlive/Contents/live/texmf-dist/fonts/type1/adobe/courier/pcrr8a.pfb The rendering of the original Type 1 version of the font is problematic on some systems. See at https://github.com/afrantzis/bless/issues/25 for more information. We ship a TTF version here to ensure we have a nice looking default Courier font even on systems that don't ship one, or on which the Courier font is problematic. The font name of bless-courier.ttf is 'BlessCourier', to allow using the 'Courier' font name for system-wide Courier font if needed. bless-0.6.3/data/bless-16-bytes-per-row.layout000066400000000000000000000016151374060072200210550ustar00rootroot00000000000000 dark red white dark red white dark green white 16 upper dark green white bless-0.6.3/data/bless-48x48.png000066400000000000000000000102601374060072200161540ustar00rootroot00000000000000PNG  IHDR00WbKGD pHYs  tIMEf=IDATxieowmْ d#! Axex Q("M!*c)Z Z $ ! LBL23̜٧O/r?t3! j]է=?,o,}h@[SyhYBs<) ,Qw㍪RiɪaYo/.cPJa˜8Z5ƀ ! CZddddjZ@ƫr*L0`Q[>q b0`Lu iC:OiTJT:g$e  S?&:1`t4ѱV jB$TFdlN܈ґIitjj@H94D.)c|:])1R%}8ec;6 r"3B$VhXƘ7A+#aAHF>RIvlA6AK}BIw.-A䖸kun})%J~RFp][-5ZiBA伾GǡL #JJR`Y BmL6şe+a ?QFqWݻ=JT8CU-`Es e6W>gS*$ "J"9bQzi|\̃|<ąs/[wrۢ۸()\ve{q]weCKyO͊+J%SfG|xGQ(k`s@6B):QYmm-t* h?WClj^܄Ԓ%7~D&#!hZs]{Ԅ∥<FD+р[r(qxI{{=#x {J!~r.AJ JFp5lHq;c,\ƦFRܾvn&d(__>uW2n8|gKx}lu_wyxdž8~Ipj#zftnSScesN%!a ``` 6ݤSid2qmX\7q-ߗD$'>84EވBTp+.!sN6X#WzW_vl&VQ%(,\]}]jq28)ǎ#?zLT2a|:5zU6Jh?S~KqN R?K~amzWtig, ׷e v _&g{&eG5&N$󂛣jVX;߈ȉZ|A>hm(v좓8t4NUTv,gC_a5[e۷hͷ ʲ\y 52 Y}Pao^eW[V~!XҊ l+i*۱ \.~jkk\/yβF(6H]nӗ~|?% (TvQ\tYL6tzg|i {>d^Q\[n 0E}l.ˢ[Dyq}5*!T!o_ q-)?{,28 j 5}r5,42L(C,mF^4;t:ÿxK.K. Q}V{糗~P,[9s:x#%x$;DLjqtz֍KYhLiF/uVkj T- ) y2 N<!$3NG(g8:z>]Fx\5} N$;|ݯ=5ݜWkq98@FN&I޾侎zغyk6+},URU y2}LWstn3 -xvKți5R OX@h.OΓ{s/8t:8,[GV0y!xXl%sEIŜU>t <4wNv&L: Jk)^?=wJZ{(ߦք&47 '|b.%8b4!"򔏟!DH%9_N I9iy OchϓL9y⇔nq\g[k߰x~C'PJ*F0 ,k -[azĶmj T`<7|q5h/'3܁ n(/˸C&3yddM;|_K) Mh:&b+5NxQ)%cgNEu c%[bˆL) J`_B6N1sdu=sc&;0+*Eŝ"yҀ.:fGIr; <~>锺7y2^Mhi<&,0 8TP#\6kaTЌֶs$KأSo 0Dʽ{da4yiVsGO}T]OaDc&`0c՛ ^ |۶q=?XoH9 T LA XR~Z:ȥ pI$N'{Jјc9{T#VƦm]Wü0<+Kz"G^rVa B&U!EoNPtX;00uݕcێgTt:M*"失0a@mjg+3f~A{w6r|c@ S'7Iٳ K}+"p-ttU3 z[դ.8L92M@K9rTm[)m=?DWWϻym.b@#ګl/sl۞ɧkNW}uOvٹ ݸ}{zX'aLM<@/@\ K~l5҉U|AW4Kͦ&u y#Cض;x x>ya bb^,,҉+)k;^SSL~Hs;u܌j>6GtUkW [[2ɱ U8-fU{zܓ5j(Tw1mBn^mwrf]r>3zBj6?!u;οxOfRloZ@DnIENDB`bless-0.6.3/data/bless-about.png000066400000000000000000002340771374060072200165050ustar00rootroot00000000000000PNG  IHDRޑ pHYs  tIME$;mU>CtEXtCommentby Michael IatrouO IDATxڔَdI%vŮ/RYYU] g$g#p8 3Uke,EUGV CG-9%_~!$5?W_Z2Ew & @LJm@HTZ_U}H`T #AW{%m|vݒD07MQӮVJ@$Iț?-C_7z$ j9A0s/dbyI.P3/߿JIJ,Eb\)5UWR`Vy/4v:^\A//? {HXT@'! 0:3֐jCtVHsY2aPXi"MIzG'i;E$R$jjHy˗t|$TC8FbW6\p/a3x_߉U}ΉFf4 !Ov1r/ȌÅr}t'?㏧a_&\ r!CL.njP55lOP ۡur_.OG2,1!u{ QFKV~C!MZUZ_}tPkCY2K +H#*lJ~?:oϻG7ׯo˪A B a3I2s8=JIs`DYwo,3tIT HD=iXiR>՜N$@2vіfٌi{q.4_?q^^CoV*l}p%!ŷ/߽3a7}x!aYHVUf@ t󝏛;[ qsU@rm2hS&ADMq<>Y)&f{W=~`!grc0g1q{ .EW?9.H 8 2AH7sɜ0  9(i:X8ypJbY4)Ip1r0cx%QӔzI/'MWt;}0e߮w0"\fP.}/|rIl@݄]ٶUVGfݗ2|)JEP /@0@NJ⨽S;\]\?>>#A29̐#et \bMX^!bS3͈RMfvS^A;@ `ޑ&YwUb&dPA2@&p\L̶bxu}JY4+I0d=GK$w.m~ %J ]a#UVY Y1y=KK@Ϛ^gU]wVGt%<+U!^8 &)2EX1=Alٴ p ?o`{e$~CMi|㔓V1p &H,9B\HAs!QW>~xYt6ˬ{m掜0Ou g%_ hL981@:%  00ZF@Rfl¡0Th" @gquX۫?``'ͨ0^"7_<^)},dGC $ NMT'>>ȩRUV9gk h0- pϿ[rvQpWg%30 Xo(E 6TQJ6ӡ(0$T@.tRВ@J%[NMî/THEтHhaL>}0i,Nkg'g.-#@g Ku`23Fri7BXɃ7vL"BB󢇊 ~"<@pu$RDX93(Pn4e `^nLt*܌OhhOڪb6OIC)@}HiF3aOr4J̕-Нp0CfDZ$}4NͳD0=-[N$e)O\me՛~?\cjg3 ,98AbUnƺ .}rx@AװѲ=kۣ^rloo]8Le Zlh"UVH@X͟/Us{feV樮QX69"P9nc! R|f eSzsuZ.ݨi$U@`" n+! F MB `(4&JnEAʘbE䙎R$fYA-^V$T,+D=Rn]^_-&]yT/$A\n>iHyJ6۫zWr(E)5-SBYnXuulXٲsbOՔfkΰ3 pLn>|x\4g|GIuwWrY)>/Rdj-Ǖ(B}N/n}̡6 2wjy!b뛹9= &b )SlcYPy]@+KEL9 fJsaI3 ǟamo޾_9`4L_KN壘#VA> `v]Elz3#북l܍f aU4K nUU)n˞ ҌOx!q\#Y\^}s?ӟ}ư uSYD׉-@vLd yNl=y~*<(r2 9]\b~ApLlTsa.:zUO]no/HG3Rv_-.N?ӟOc_= :8' Nn#6mrbd @H$b" 4@%kDHIhYO>ب_osXJqaIF93!M`_aҽRdqI %"u `V, R2j KcKYxq;z'JGgjCm'Oc ӝBA'OCG@0񳣛5R*jn?n˷߿}mdxt͜.%{$m[uc#AoyLr`32!2.b&in4f+L)TS#JA^Ya//}/4,]}ZuwWw Tæ,2YpT4F2{te3FO@rXcD:tE:ʽNpƉB;4`S#Si|7D˘-}%u~hI../o^_ƩWaՓeD}}x3tz~zsyS./ Q)yJ)Y G3OpSwR>>Y b a?b܎ݢ΂ fXEX}5Ua/S?ڽ 6sqEShth"QU4,)%)>gjY>вjfW`Dkh E %Yb\X눐e ҡ )̹立g>jϛq&m6U$ۻUhD8M%]thERP#Ð=aLtҬdRG7뛶kwB#6ʢ+hbEIyk O>B~{yٓ:Qn4ȜV3"P,H +;^Wg|wwkm*eh[L LSN6bA؛Ri"X~7]|(;T vv*/MD?쬂6Ca-</ӡRG+%4)LJe/)CER.PHG/7xBdђq8 i6w'gWӇmJ^ԏ$2)D!i¬[*XeO^S׭RTmE.cSrYdM 2MMXߌ!^~?Ň#B ]!bWX5a259 sq_~~C]L5Q듐20pl}"ĕ-u[7oLtkhE 4~uR7 B'9v~2*zxKIn4O짻O?i[/.fpiw14-1gOFV't;9={B^{. ǖIRVՅc}}Hn8:?TwMczⵄ0 c@,AШB,UQ(vW[cۡX$M2AAju-Qfi >:!zǏVq8M>"iB ]Kt̤Q48s"`DZ>i;ݪkEq֙@ĒʂugETW06``SsWt/sXZT5PBd48tJa5ѩvU?'~^_~<./V'RS6fcڥ]HUaigգTCR(bԸ! 7Lp\=4Qn &ecjzw|O<#x}+ B{Fr^~4c8TJxHXe-W}Ͽ{ ">X6tZjŅq1f,s`GOfj7>RXDu(&,{*.*UyuL_M KA;(#\91T UZ 6`khX#%ANbeje篟^ 3t/' f2kJ4jiIN`-Oջo}v5!VP{::^& v2oq?f>wؼ_UC]ِ|DӥP c(FZ:0XX5=pRBл9-K F50)+KgN<&F9P7h8V3?T_|?{nz}YU{5Q/yTܚ8`@9*1,rD"ZpJu-/(\;Uk@9࣐ԊzLUo7>̛9~\ndPYq@,MrWx?<|06(!9G'qqTqQ<]j66IGPibЌ3!ht0 a]VD[Qb2cYYSrDX]'[x7W_VW  3g'1)zn;l#nj5Kq.u:߽i -5!R͓ͧiov{ۋwNEpbGB0ޥt'fnFZWo{_߿.,̳Yq`"`G&vY9Ar|6y))^~a J+, -`aUeu^_GY4k\vUAOK4'ɋh2"Ͷs`Y}F# aهJ?ϏÜ㓱ֶ>^Tu}ҝl DoWEǣ5f b ֤X4b:6G]:cnd}(hys e >z}d>XGr8d@"ٷ#L r1A>X 5_mz=Ww23SY) b r YLYb7% S.%E쥤rXΟ~w?xpz!Qô,j 0du:9JnIm20*%L癁C JҴqH07Sg}01ys]w㽻9> yan40P*Ag"ٛoap7itsȤ(Q'tcxE6*(40{K'Gmj&c7}9\qa˓&/껼MSbrdlk fM[<2(6h0@Ć,>d̳i̛%4´:?JT{]Yhwoq;)f4n \;g Ѫ[~rCWk`"<}V2  .V+s!e)\&oMQ ܷ-Tjef__Z塘bڪ4(hNV!<^ :kRɊXj'G/fwSz3ʕbcˡ2 '!Z8z]m XHГ8/)UZx#o%EȕufxNۛC4d5vmdu{q{vrU*JIwX7] wwݠ{|qyku!00;_I)oo7F>!ffM'86a1T۔ ~Vr\,}1X9m0-RG%df?Kdbu OyҬ͆LA\aa,)iE1oSpwswq{g>z~M2U|k-~AՌUfh$av*̶[.m^ԋbw)A1"@sшa?`iLu>i$H*'\s|dnn=Q &(],<{vsy,"Dp8a<e@ ![ ƮYM,z^>X6]oxnǪ^S?>6'v1LJkfFgc0h&3ҘKhěd`VI(u0&*z,@C}T׫*,Y$2rHdpAr< )0 -B.v4E-:" <~'n!PT5翼w? Vd}0ڞ~46jĴ6{ @irBE6d,4&>#X}ɢU.>l:]!a)q<s*)|Nyջ~`V5qq7ޛӺwHJ4CLp<<hQNh! (lϚU1 F1 _1<9A#8o_ݦm*Alb=R&L'r|3wW n^_cF7D1{ b0ɐ2J& S'f?zw{j zvsen{z亮ݶ߄':  2ʳFQ?rfYpzf,vwVbBP;7ܾay2V1^nyt(.4߲|r Rp(i]ը9X粃)@a9>|.%bī(d,~`wz4XS\=cǘUƳ݋PG m[a`u1ɛ`fflL _&4I:;if~vx&9X*]JVpd<qho ggΟ<ܭ_My@ ւe/)=aRmXe0~j ,QSpOpbu¡,FnX7?Ah}O۷6NHēxwVN ^%/ԭx+p15\҇9 OeznQWuYJ\G&$OAwcٳϚ'˦֗$y(%eL4B(?!ᾫ[ZIf22UPGi=.tєV3i?E %J4X̏Uw{K7i*s8<P*!Lժ:=9I~~@@wܼ"bX6M~r.PdZbGutCs DY9s̔=g/R&7swԔ ž&4L,0,Hə\Xg$C`2dy}ڍyFR$wIˋ5mڥ4dYX,\))͝3W1Хs^9D/](;HW.lBDDLd@ Vn e[@aI9u'O!82BcȚ,<圳CPa+SiNdR }†d߫I}bލ+1i 0pr F-}?guaERvH(YqsA M fWM*RX,%E*ϩ$ QӐP )׏m|;fNOۍqg/a-DCIAG|~zۅ`z뷖6I2*v"|ɳg{yZd9$!˃zeF9Tpj@{ !fEmSUg=w/s5߯ *Hf%dkeNj"s.\22%1ֱ/>_-7qUUmĎ^^wfH:w~]m9*'(;0^uf)SO|5Un8NVo/}qb$2Q {\,ݦ%2;VTI1gWBjF[0kQו hrY@|??z|pW1T)CgQ);&  G hWǏm]Uo~4e; Z` cHSMטbNSvj}Z>;A34ڿ˫U]mh:c0ۿ/0ޥay1AF^}6_%a6wC ^cbռ_cEAgǻnz.N'3G)PX.~rp_E QgO.VYӴw7a7~. ,FIMhȜݨ-b_O  S`DrW92r 䡲<ò3RQ94)&*BYLTC%yS{y>8;Ә}ur&%fg@PʚOC W哰~E}Ke] v:Z_w~xjSx)Rv#3wxyJ)<{oҴTۓi#Yn?iVCx󫞢^ɟuM,;,jv7"$)nV!+\pC"lU՝ٕ@>`f <"Xߵkzw.,Aܩ=aM¨i\asFo&d:r5[-9lUOZy\'~Q J8Y-n.0zXMw;9+jXLm`?ɬ`Q͊S<` 1l؛fK>$T 5M9ff90y( ٹ L*xexd#!@i3֩%:`AؼICyT`bĞj}1ym|՜8tNj1|1%TٌrR"\5 RE$,UUr&)~93 ͼm|^|S/^Ԥ$\^_@o돎ݏ[7ʞP< 0qMƶZYB >-[2>0?sϞo_W̎۫ 0.m9sE(" R, cYo 5rd H8 >N->;tɹb1vIQbj#!2׭ǰС٘0GLs.X:"e XԘƉ J-W/-Ҁ7w7뛛kt,ƸX,v'A8>T!" v'Cm/"jb(б 9/ltƐvfc$dnO5-T;Bt~tvjC-QaRapXy82-7eliL|luКfuCc]肩.WR*ېAz"M3dj.qR \#(;R,FS(qs=x|YOp? :CX6g9`.H]낥ݶOycRy}ٌ7F`+T+ u_T{W8a LiHPGYt',*jf"i{s3 1$_W/yDP$:ЍKh Yʍe[Zh()2ilWӐ> USK_:8vuYn '(sCإ< JW/onڃɨef0į QG;kJ,BEh43R"ռ@Ȕ D "6[fǑBvD&"a%Q6r (3A<9XW?~_VFum3 o:ip)JL̈9ԕgV+BzM0Y]5vn!I᧗NxLbhU3(K}XZD c' HD%F7TQEa5L=Hr1 Ѕ~#ŷ ޶ k>fv]gբUbwiR1g0 pId ,''Ϻ6l `윉y/=d7) ق#)Z!k5X*!`=wc_yj*R,T89q@aJv> |&o aE'0;˻8*"%T`Gwސryzvvhqw5!A+`Uel bt%8w? >s!.s"pJ9z<%H ydR2x3YLfFU! dn єA`\0H, w%yO8ޏ$فLzopDa?88fFdb_ ̤Iw?R7p*UTE Z\RTЯ KM>b)\Fjn 5?M3{jzU\'5g'ͨ7M3! q$` AX,d;͋_rd꣓Ʊ:_"1 39"3K`͠@;S'<2)9@J.?~zyT$ oKb$61~21bľ4͈f5@4;<>cDjI(w>넕mE*<@bէ,p4K/ }3[c '' P MU\*Q;S::;RȮ{么9 L|Vm-³]^\4r<{{o_7MTGET#Ӝ#)B".W@up ( SRfePja="(%]񣧎Z(xD5&@ >388sd5O|SO)8W۱{S_yj+;U냙x݀2=fJP3 cG'7?J`L@šxBˊITqsVϯ|ÞwnmR>=j25U zϮ}/=y-xO6) ;W~|`UZѬ^.74oVxӛDe;YS3o Sk7i:#uZrFǟ4imū `vtxxuq89Thfߢvasn:7: d̚cw*1s~l^_~k|ww_GMLJiL (x@\/zU ti+e".t3#'$A2:tT{k$Sogwo+ST Ÿ1Tϟì^4`{z,xw} 8FK`OJ,ϻyUp|39]_m,S$7 9a7>~r|w?:f!cE [!0`}LdN81l9߮/ iY̯|fpfseLUsA,dUβ G\3|X9M1 ^կ57o=::Qӫ+>`PwciĀJU{LIUc1;yUD,B#,6jۘ:Hd,e 61Y2 |T-/_~/͓4nKƖ4dL.0"eNL,IF1HԪ<7p'㍰qM#`~\K@`O݈l 5FOSƑI|O~Ms@tZ wc&KQ TҔ^]߮oEc6۽+c1HYHQk Dl'2*a#F (ͱi IDATS}0sxfU_\}lgM*dAP䆡u` %ƴJ5P3ȑ+.uiȘijWyCNxb. o~d;u#fNQDQ{2e(d ˾ q|&*`*lCtfyoS<+1C`U2v>~vvqIWW/_h`;}Dʢ,#r_.KlX}&侽*1Ϗ=i22, /%'|Nb+cѓ~$w7鈴A}H2V(UTpE&\ Tş;"!co<$d9H (;&v><80 R5Rk_4hD2q0 䳛T#s}X- #m|iyh,1Ĥ=:=ڬwfqr| wc 1@S(-'?فx+CO8h'*;v73S*A$E͛>Y|2egBBO6",V]UNY&-2j$&W?kF 0}.AHA4ٖM7yc 7gؗS#;huN w–Ȳ\Ey@!(&I)ߛvnDts{QUתVյs^bN3/mcUM #SQ¶qT;N٣AT հZS<Ƀ=3 [ m42Rc g @:ψ(5"1AF(7:}E-P{cT-s,$/QX̊Sw f@ie ]&ʻن73|ͯMH >yOr`ّJs|)qZUoѣgUSm6ӃeWv $|u~1V+yf6^nZFq}n9ld,9X+b^sY7kѿ|wa Ϳ8''Q{DGs3kϞFRi|Si3GW $ ^vڛ*}rz(g'QEBT<=gRS1:t㛟޸yկtM5+2\.Hdyp)f^VҾ7p$$^.zÝl1iL**/p=#rY Ol7tNLƫ'rtpx:|헇n׳2T3JR.;u4UM ˘G` 6rޭo!dJo^Q3 2QsjXK%m?^: љ3\9MѻTк*b1!ǐ3G$Z/;,oȽy#6"T #bޓhao~zٗ`|&%I` WO!^D!Q_]KZBCB)Sm-IHI.ox*kbnTsNC|ë$1u!KJ@bΕMvcy*|LG(gK'$OalRH{7X"hUKO~!F&K͎)Fs94'rѧH+Kp X:EEq0 1&F`FvKF$y1--ηk#>;[߬e,γg gV]v_~u[/fks*Wc΃J҈$fgלisMD׶ ~W*w}]Ov@<Ӆkj(iE)$en Ÿ,Y>nvc&I`e:88q~!,LfP &ۿK5g_<盻IX4FO&Bhv&{KM bAW}⪳`0aUlFGUM3k릉1 j/1|A rtjm]FBg!tz|v2_ dnm`$13J<GVfyfTs fvM Q6<B t`J.!TZ&)ZI1&0XwڷHE?kfϿ|qvXBf `$U1[5~m 6 1`I@au @1~0FYjmT5>Quk@u5[noί y&tǛ5*Ju7d,Z;muPv>X>iU!AS5%b8>>ݮC7}Jɘ$ofxPŮIvPKfBN_owo-ξz?}I(A] 2?;ws_MeH #D ]U9V;!%.y(`1 t92G?:<8n~}ۄ.ebOJvʊ\1=>^ krGVK""7s}< LJ|64[Wxh9jV H@)#!*αc&f(g.O g)4/*6 7Qj2r%_>o/^x9DyO O\7D5 ֤C7Rk\ay}맿D)۩ AGmѓGùUNwӈse~qHU3,.jTv۵W@qqH]'Q`B@BpLoV%2왔.DRu[_yfvr%j׾+0딜k&gʻ愚 ; *0*l@F)oXsvuio_ ߶=5[dJ l t.ybI99DzõYJЌŖ+7HAA3oQg7PJK QI@ȥ)I;̙"h~S~@p>jr4 !%q+riIv}uq-!}a? RvIt͆Z*``Bfd_|񼪪?=Z?(ɓϷ|v HCђpVT<90Q@&SV0苠H R9b.ren2HԌU*TRCɊl#A͑r9ZR.K/MSK6jAV"gH*y.9&84hw*˓,8T*4e:rw{i4*IR*JE2ƨ1-"}ҿ|7gj%oJ q kj֏o^VGM+b'>7"ĜK/MB]}7I!36پ)@tP{9y͑#bf:˲9$?W${qKd&H[єκЧp5 ,S1u4C(]KhMO2FRlzQbMw|{ mOۛ_[tƭww"⛪I5nz 1L |FEH#g&uPK'GcWNi ;z%2mO>ۏ뺎Cg'Uy:<]ۛMCzbyfY Rf_Z)=Oٞ^5b!u𐐽M;f{ nϬT^yNsef=s#*fŅTXlu4b.ޜ]@`F,XߓFk̦gS^0 +ƤɗW kzT-*1)L͜ }-)كqptzدqa/>yv6kf*ZUw6} 2|p޴Q)eRg%7W0)L5@ iRwVQr1c,Q.;^p!o1t\ejPM)&CaU"2cy{M~5ࢽ+_-ͫc^o.N 6AAr~QNA ,3}G&zQJP5mZ+LHDip10f6DL 鲔 K9Ѽtklw1ZXv[4M88:c AϟC|]AFQ*T$JN$syۦerL}t3\E+BS5Ffl؏yu"^oE.xS#ۣvYسDb!eצ%3dT1WmD~ȩS8ǀBb۪ :jv}Q/sbzOg̣n=RLsbN)E^gdwE׳C*ز:6f-&(dM_^OMh#gR1_l`*Jf'l%WmS8מl9ls4k/\z_FhոdHl/fUW﫪&e@'5FɪF$al P}X*|dP !9U4SJB]<;o0M6M.oFޢLuڧeh71[YQn_}wwwŻ!!  f,fJ1fEHg/(73&ah\.?iJj1''#b&Kӷ箃ҫHJOO5S"j.H8Y1&$nٙCi).tUU+)y7sVލl Mde{CXA"GL箩g1ih#_׮r.眖7J@`o25S]Z& *agEKӓGl6𽊔=R#ʚ9hbL,,=g}?q,ZQs|yp}I, ǣ_5뿋oW[cVFpS$rĹM&z8̧]rϐgf)!Y!kcaHa x?ZUs^w 77MFvc?v+ K;5dxS}Dv`V33*כ#6@UwuS'In{xtQ ʘ21x+ ) b=;I.-8ϕ*ލۻ/޽{fَ:V8;x)HA 5G1M2l䢧B0`jt81`fI#yxjx IDAT>&gs*rxwcE@QjM>Ϩq|3&g9X43 p08ux Ϩ7䨵}M1}حzg?`D`_y4s08}@٢nTurLW{!V`"}UJ?Qa]@xٛ Eye]awjjI& BPq}LU/ioŃepQuPOB.H4!Ue@1q}DL3a8lUdM^D5w:1!p|z[M<\u{RуfbAG? HZgnۥ1eDsSI#eKqKՌSN`Zq=OlfȞ0J$f${Բ /!SrSݶD,Q߾4ȢI?#LBr5CT`|MT\SgqS]U)]2|++殲p>{~yX{es3+ 칞Urņt#dW3z꯼X~1^eU'p#ԜA$LID8h)4hq<{yZfjuu*x;370o Z)H0QΗO#(v}kAM[f5UCwG(›^uͬcaG JV# AUL6nО4Ӆ:nlN`3 TT (Oibcf燡樖w Ǫq\Jbpf9!lqdY) bFݓmhGJ$ξBzz,G%̇>~'4,ın#D )2 @$́H 򌖸%DXP/I5 FB8UFa Ÿ5f8?+O+/Il(S3*V3O+OYDBzu''G"v#D_{f;d;oGdΈ@}GWe4421=UDvE+eWwU׀*砪VV 8;##<ºZ3HAgd'wޮ<4]:8ʹOuAj濕*Q !ǟMa^<{s U͖w֨ R#3bҁ / ~uyw'hB~ LK<\V7_|͑w%#bHeXЫ 1R9C,ՠ;c |K\ 55ˀ2D ҋD{J)yUY\z(>6?|pzxz|/WqK߶VIb4Ls.+\\^ezU{v\HݼXviFGGǟ|/WzXר˛5; gL6 ˤY]\$Zȷ 6VLѽ@[4Y3c0%8J,T'6ɦֲ9j@lPFp=/p_y_I9&`Jm1J:س6W\ofs;P17aLTn _>\QDxgW[65 4lAy \eoQ\I8Z& ޹xyd !4/o6eV~WeaZCB 7:Jhk1rǩ!ٴNᚖ;͎PbQ2nыi{G!YH1ZTn%5271:c 24$_{f~{e!ZCl:_Fmvu֝Efa}Lk0!*\af!b%&4.U *x|Ws3%}X⫷ۡƻ 5T`EXY;m?._=x|_v["f yHawf "nM?{ml~)PUg8~Vb)TGG4 0j`#s"##XgGӓi3v wQ}d);b 9{Nޖ|7V\sUͳeE r| !YRv~pyAet[xސs[ýHF?ˆ,@ɴ C!DVT5@ fLz)܀jɃluL&>~X.XU]l']\!qEkMiT*6.EjS>IR{d45{{@vxz=5V[ZՃҢ@ØN;JnWI}ԫvogdEz2/;w T d^?3~GԴsJYMU9$MfiՑ$M ]6梅"~ݓDّ# L̰D @1V&DhܥƿScKEλfڜ_=]]m?:~.9MoPhZ1j:3A=k ߛ@oX&>|ԧכzﮦf 5gM]Yћk}60"!XXPu}w`Lż6EfUK)EFsjcؘv֧d`6Ndk;iEՆ*86cF&*Yl<Cs7Q:ѭNUMTcȀ,*ƏUZRQ3Mېx@,T4+p74d-|tr8;}RuGl*!^&z`57@da +!:1o IId˿χͰ]M[Ohf Ġ"uZ&vp<ͻ%O')؊$ -x6Qj)D?!z%11dwiF6;>< ã ~ƕfv2ΖX'AĠ~v]*x[V~D):&nƊ5Iq>_%@*R dDDJ۾&K@`@44`!/mhobO۲0h+.T~FFY+LLojݮ{>Rݙ& d(ZE%zy92@'h 凈frYJpZOã{ݛe3o&'b/veH !`1 \ m{59랤1#,-hʜ!Qe2Wx7Ka!ƦbE,sp=[5^|ɒ̆)eU՟(-w)N'@Fģc<<=vi/0ZjRlb-EhBC#¹܂k"f {"Etu.ZfmFmS)l2iw-Tid!{ b;,Fi5 `w1 ??9{&σG{ʓ84at];16:#`^_/PPxߖ]REڷ0g%k3|x|őM춡`jIR jӧ˫1ݤ3n<"7#Jf3/_o/v<$@ 4[4؀&Ė!zMcئ̌JQQfZqew1k'+y|crkBRG7Vg>iސGIUFUY$Vqc ^zKE1R`Gt:pyp\.7_/n!P}Qп'/AdMJtapU A)B *a&(64ŅmzQ`Ŷ-,uE ~'wgEz-6Mw]ݹl0Qx]Өzu]uUFt#/XeefdyZfqédW@UO 5M`(7ǣG@BM Ѡ*EABj(pX E{.닾;}?GifI 3*/^Dŷ?Ͽr۔+2/ XXG8{뵆ݪ7s@Ï'n6=G& 3ߍKw6g˧_?-E`)-SM 27 [RU [krP/}UiZ.erۿi%:cWXDT8ugZlkتtH)uJF5 Nzn::6~ه$*Hh!V Dc`R SmwfGp&DD-!-pUHPp0=xqBCD1zOI9}Jg?<g۫+3q DEڤ`JR8Ɣ)p%PX*&6faF{Zqkf٣go?|r{,V#Zqk@ŷǎ_(TYp QVty? U j!29*@QJ HɢOR)>(F|`xx)1[LZPcV7IX#{G "Bk<p^e%FzwIڥ? %eqnY6BZ6/)=5{^LijCZL ETԓ tx0,B5wLL}r-SD"&5mu.v6^)T᭻QT)c٠@Q,xJ!R좶VO``ܠ !lv {2o9 Rb% Q]gdOfAIYI{ _ac2GR7 XoZ$1[UJjŘ'LA 5/չ!4(3o'+'FK`Gu>{zqvwܹ<;6WV3u`V` Hbr2)-*U!muGmdj(F#Mׯhs DV54ހU%E5y'!|N;ZZ!:M]}z4?}tGY$xw=(Nմ(FP!4()GPcAm-ARywMs #r8I^?R廫o(WNroN&nXa&Rh\ q!2HicF؆9h!Iz:99\N^?Ҩi)P1x#TL}~¡1ʶJ--ȻsN}7MС ud3R m}G:Pȃ355i䆐v^5a. Vmgw ;sz{YF℆k(&0,?%*ŊEa ZG$$s01JTXZ}<#~g{mxM lgx$2s8>XcjACD4wauX ֻ!_}~yy-17}Ɔ W9jAQ Zj[ vFŽ|F{!c6jKQ_Io~Id2FrO~8= mS$߽ݼjM^mUp~묠+e01P-߭Y1 %ebJj⟣OuIJB ZKJ8ƒ=CqR,Ng?cdʤaSw2(*W Lzyb=zCJMF%j Mm_ݷE LF0I{r/_}lGK<$2EɑxلCLdZTndMqq_0UNWvޏh!4mӶ`x+{Chǟ*E}*LFN8\~H-թCQ:}B-#Bc06޷\Oy#vѦjhav ZPKd$O7՛Y&Ů.?2+uhnRBu(zWu~U<XBHUڦ9-ʮŗv`p|`:*;QmEOo/ώO=H)m>]{0:ijIJ@qbd[n2~dyaG$G,hVF-"nH#STeL군c2Qq$ZW/|6eAAM볍b!UuMG->8uUA#O mw|pgQzY^.CdLȊVF{_"t4;_=-}AM6 SPȻ _F#4S\8pK>e9Fbȑ{?XD볢׫" [LBRx.q )gO?wnkװ>_>C<u dFFzS6m\~ѣ]x}ф{hA3'@QAhܳL,TCHeUm.ZL9~YgcHU`/{s( ˧wMw̹dl L2!3zBfF#RIخo ݙfequ^eiSֺ@\4;bՌ.C5nNJ 01*.I*xC͐5ےA Ҥ4ԮʖTu;{LtXe-"*YBU1{x'߽z2W3Q 4F !!Jh:09UGY'p~8#i7{g-BGSZ{nwF6{MĒX"d4lP$@L}[`{ɍP|v\y<ƺqJ+VpcP}O1be^]1pt/}s@HiA jvAJeC ٝwϮK/ sQ+ E@BlXU nYT*{ 9 (C$WW!v^]g yoiДԄ# qkf. lǂ-QnjXGMAbAY{M "4#L& ϱYR1},EYKфx8((*1Q rhÁՎm[Z6i۴mӵF5ji&r3lz0#%؄u9_^~˼`E-fCPaBf|9$тJg3۞o1`neorF!9T+h!Ic"*5pxQMM亹|!rZ W.~UŊw _8m'AtHVr5v(6vmΔԔͽDF7說5 ٓϞƔ/4SPGh Z™6CIS;g5.(R3zjGl?x*Ҷqޜ"nv^FДJN^_'_YĞlfTT)|Vư Ds-I{LlǺ^\πTvze~76&6fg[f:^ro}ͧ/g$ATYo6DY&L`@2vԸ0 ڛ%W/m8)n#~ڮW׫ "BTG7};E*5_v++W5VU ղmufoBDTMjR )Ȩǭ$ A544B=z{-N;T,=.C!,;2-Vޝߪ"Z؟92qZ͙JJR\9ϹUCա1gi?~#;b; %C1ˤEYճgh֠~NuIޢ%6ay1-ѓoD 4r !W]Syz܄t+DeT>Vti{SoWwCH!ަZlG!R :r[ i;oD"۷;=:rw=4lq:46o G63,P T&Xmٜv'B;Z,^~Ig8&90Uk 4L(,h/o-܏lU%6R \E 倏Ŋj6HK,e\.Wʤ-g\t(&ȡ}Ni@SYMhLەe{nR#Y l 0T^~2|}M , fP$j\?Ꮯ*K~}Ӄ\ |(XFǦvT}N#HR00aJ4JW.{n \bg48F:;ү7؅2#l0!My;;R.u%|/c שׂIkU3S)2ӏ\h*nKoP_fWedV !̍" Ɉ@pWA'IPޏhȯOm"#@fFLu|889H)mm=ajo"6 I2=yr %EܲrԮwOsܬta Tb&0m-^82tE4* Ct:,Š 8S2)-8½ƽ[hz5]Off`~VW˗`xf\$vkLL0@xª/ZQ1#Q,&Gw lmaST)'wWr ŴŬhΞ|_|{ʛX$b*fBSf# t>35 7Ӧu~ ln PPQ+ddjgoߝmb/?&iJ*R#n|[۔+ԕ`'2njNWB@Lp+j 6?>MFV#nc7iIѪ  eU<8PrٳbƘL8J* TqSF_ Z*ޖd(7KDL*RPZGa&۴eKΏj`ٽbnM*QL*oϖK &TrB!ሧjJqp@jbx6*K BHĴhsq;idzG7_~ٳ/C0cRbD@c tsdfRu-T85(h`2Q $yb#5X նRZ;/4ЄcD0YE0S4Q.lzi[mׯnCҪ*DћD9i$<`y8#W}}*m:cPC+ZeDNN~A-s&o- AZ'FqdH,]3W=d yo"9#!c7W38̺_ĮxwI &$c>Ơla_ȷd{' yٛF"L`o.,#Q! i8"%YNxKNvL`g۽ji`LmmޖHM,`w;Rp YI9rj$qSlL\Nb5 Pzqc)v̞˴Z%Y^ZŝP'+*@e|<О BiqaUOwuP}+1Ql&S"yMxyaL_˒%}`HVEtDќ2p+P2}ͷ,kY7ݬe]B`?:L BlBf 1Bd̡*[B?Vc# ABc9ʦ0zڶ;r$dHeME P8ӏB M~t7g[9i"#Ggy6b28eo\URTɤ1s|ݢ#"**kLGx"@iz+Ҍ da4gƎ@@V `@FLMdyOӿ\M-GƁ٘FbYl/>~2AZ13q<5@[%#&x;)->:|{M:6wQZp~3] "ap* rU )ˆb0DNMhkcFC5TqU=ٛ7onD #`DDL\[rM{wzu$":A#F+`+5&ѠzX1uKynbU#aحή ٍf*{l„-)f͓RN9wڧ_=h;ds5+mmV7fC A| W܃gbM^feA.)vq҄64Ԙd33Dh% X9r:7PHSl2A FsK$)jBp\ 8(;bcPNctP_SnY_.G{zrwRoyv۫E'n:9JHvtQ |dj-.nX_I[nXVmԞ}Y^.ˢPh~Z7r"KyW]o2 TVKkˡ-Bӣl<[ cmwZ"D{ٌ`ȍ+A& P0Y"-cԅZjHm7(bTƖ<̦w?!Hԅ\38 wpV.Ï{Jن2oߺƦ>iAl엟7wC' $$FaHNv8t2Dv!1Qc"Ej%PNOIEzp8;Ҵh_pVB̕6j&$'N VE"?dh5_9jYw-ā@dL)H?T+I#?|*dڴ퓏ON<u% >805DqnC,ϻhR0Iq74MC %HHā4ΏgJ6Fٌ}eCm~ovݮLD; Mxz~b{ѧr;r;mBlM;qڦg߿l^o߽xYIi{A1sQD8s=)HÆ1\EM!0s A]]iЄFcgfٹumI3X-dҷ&AD{fTNcюAfv<]m6Fk: F1r 80ěs]VPN8F2Q)VR0+im'1lT6mEj# 27BڴѢje3y{lI;S 6^)}4MpF't 'x[ \[#"b6 ܖL%U%9j[„1J7c/,Qca߀ff:\ĎT'ߟGu4Rb/ Opm q ldRE `%-bsZ AU*mlwۡ['ǧiHj(?eodY\gU;3r) \tUOuH6@`*+rчpfP="3Kψ 용;5u,& uM7BH ϜkxXXɳ)9`h^m{T6N23$Q0EQlkC zJc2̂A0V(U*;W}pWo~E[.T)ecwF?F` Dg2o?S3S||G|TRdhK`Բi)u㍦iBm  R}trddo^/ev3lc(P QJU9Ut +ykV7k?_k%cj>ƱzeHQVD |<]C`c8Oՠnz_% rHň#W[uмXbf' ܼY݀]&)s(aG\0nwyt?`*L\@EQ_})* RAAb7vpfo'ѿ ڬQ<nB!Թ(P :JU/)ZifHLCeSG׵%T,[3sDҝt﮷TjJV jʑuCpu< IЅjcZ*kb:4$'i Q30fVL8Ydb05)U!6L̂<{:_w,3(yHR"{yXjV=i%mb NYD6ʛLA_>ٮϿzgo~9TkHI+;IU_Wvo0%(l5N>aHAzN784jRK bUU1 q? Z߬)% %aOC&H`4AdvR4$,')'fj3FTILRf>QqTb IDAT)s36V*CIUk0[~Q۶_}{) Tfjɥ!h1m>QDkNLHbs,4\~qf3"QsIb>:};7%R d\Pw[_lJ)׫k4q xC-l323ۖļ D]-i^1qK(6R * 0Bkn~ccX{Z[0Bo77zj_)*)-A*~ޚذbsbhQ|}'YUI!_']Bzǟ~ݯKVUɔ+~N؁:L<!HR@)ߖOz+ybO?wHP!IFS}WiwΒ U6tmH ` B}M')*sΦ5uNB9CAƩllkѿ{$֦\5MԬ'4œٙ`#h{o{ 6lwb7@NAߟdaT`S{iom4tcЮ0wW}Ӳzp̫'cQKݬ NqxL9jzuzt_4dUUzuǔ2 ʞlÿjl/5sOշע(0 nPϳUk͖(@?Sob9!u6Bm$!OH7YvOr18+x< FmyoABoWĊ j@.-U`nyw ރMC,NsO @{O[3݋J6& ͡z:OafF*; *夐ê1[Rr<):+ЌJ/Pbg4Qű"氲;$\mV`5iδylò~VEm (D:/&1U4 IF!cr LȦHzn_4ypz6/#KyZ?ǭ6J75r,qӐw;*s6fѤu&i k @z:1Q!>#(GM%-eoF\BP xuBfSM 5xJ_RO[O(ZPY1F:@#d`p3U4ZzB!P!h!3z^j<3SfTt쬻bg[˻D-wFw60$sT` -7mQm 8cmv %7Z> `|ՓM l$wYڎ`i4}_RZRCln6;#B;zX ?)ډU@J|=\۪Bv'~: F-G,[f@1Hf%SFaT1_-k6YVJd06¤`!sJ1b Hu p6XZ2"բ^, b r1'fGd~EIC͊"I8x-bC6񲄶PcL9 P8 ^].r;quOѥuN ҖiF&a3 LB9$3BD"ir2?Tz[C;4b0@5uFF;tH֮Fn;}z v+5yD'=5UEzۭJp.yS%54 āXdhP20w'܄&/ry$;–#4La؈4F ԅŊ/ ket&~Nkg.OO7oDHuڀlavK\,=!zkr#LT]!GҘ>gZk1mstz 1ؽM pgvLbrȿw/5q.?𫯿" 8nڸ &a0`.Ro1YVWe%"lf!0%:K8lL!@@/{ӧO={7.|2L:%.cX+ BEAerﯭ*0~#+8ڶmw[كNbߴ@hAYFcPhjvxwI/)rc4tڛih2"Bch˔:%5z!k6+1&o_v];M7rXJˬi.JFµw~Z .́Mi"ɦo&ʊ7oR#Υǝ ̮N~-.qɊm?}>vח"ň6 DPˈFQ1bݿ*" ĘݛuG(i>_4:[q~צ]Z % g$)wQD5CBY&IU k]XA&`0K@aEA (o;셔L M2(e0nRimhAj>34]_~cB^ QZIh5ۃxOyKه3?$=;Ξ_.JN% YtzHz)jCfْŒ)&y2>?/}՛˔\19sF fMt6hܠE?*n d"ݢoBLTvIBhbZ "#" ǀ)'ZD1ώfM7/w:A 37 ɒX/Z8LȌfG>zwr ˓fa DH`/fAFgԞEF&T)PXooon6G޾*IgogNaFZԛR Ewa}Q6N&mKa!ɮ4;55ut́8)ipYΥ~u<`&L/_>XhXT)tm,WQNPCp+?94WկØ v'OblڣfH" 36DӶyV6*VlTLVbi_ތQBިlVJl~\1JxCA&ɝ`]~כ/Woƽԋ Hɔ416()L; <:bTX،eQ8pu QD#I @4;~VRX[,o/'ljQBWyJ"2>ˎC=wSOc;1,#5YmoWol9J<5[) 6 ј_r{ϖ}ӄ.i-MMe6 jdNwfv]ea#WãgmBKIZP!L'y*+@ fJƵzrj\Mv l$g?9LR=9_6-74.d%fw/lG_~h\ .ܢfU b v>g*vsu_W*Уtpl  B.ssPG%ZU"PygiN-=״v-հ[)L  :uT;]]Ai$,D#q r/{%l~ط_}k۶-cnQ5^^nzBTMwEUTvl w p4!1q Y.7ߙT%SlG$Mx?./=}rf~E6hgڡRh亀E,:;C.9ψ>X._]FaV2C?`RE7q@dC.C@$A`fj۸% ʶӃ8>;: W2٣c3tEŲ"^vH {G`+5SѴO;+)t6ps*,@ 4D+г'UTCSB|>m7[MI#qKdmщH P5Ա'2=ۦ9>>6D]\6SQP6w$"۫ϻP|L!D@Kf1lVE) aQj[FpG(9ߕLQ+?yjL{-Rt|&Tq5Y)jbΆTSo{a~/5wc<[.J'''cVa%OiFL \{31M *5@$5oBUtݰw` `aD6u+bKyL "!P&IP3V/}3*XL>Ųwzgq52;vޓ{6rc8Om^]\};%!!h#*E8)V"P%r.`uFFhg Ee_5HAP5j.}I5K(1` 3XV(9f:m66}nnuɦHC^lw7Cl>z7UYU|Ac`jbK(L}T, D9d0QttrѶ~8-S*$dbF0qftM21ގ%@jEەu1ܝiMͺFI=c܎o`b6"F`djøxc&!KI E:"f3]D벩 1Qͺz65aBM4x''0y2ʛ%_~޲Q״ݎHU݇3UwugA!qia'3. t3ެ ݽcWUDfcp_BJPI, kikȫY`bPF1yȬ%XhMKʛa2?\]9[L$;t`X況H!-hބoڦo@Pu*lX$ln1%3<;<0nAr(d0V@7(hqca;CϷ!Gf&̬/տ~$HNxHbJ q]~V\Y(M*t|hv^o*eoVlb f8&2`OK(֬T"E.  =!޼ IDATQ0T\iJb,uWhƦ&T@e0C4&[HXD'/Xoo^'lKZ2-uMqу٢?wR8h#wCQN0r.5xhBr 0c&UuyRTgon}1U,֔l8!0EfTIrLhRLڹOm>yK!I )(0p09hADnexa4=3y%f1u{Pfތ1d3s,.["q}ǠPUޯ2$FiC#*S~ݽ1=z'q~Kf^&J|̴+N՟Hy7/0GZ22G|@E;-'2":@Hn!z<.kEhXR62 ìI #>XoTݮzBb%QDx{-PEi10ƃvxfQڈ 4 T`P &2F=d躶B X#;`uW>䃶붫 _&l?\:彔}N,Y@۫gtXmjlWk([EJ\j4Cn˫59O7ǽفo)~8/]B5P%JE+fݫMg'~և@RU]wWTYOi"tD !a6\i)tX}Kݛ`4v8[pݼ[/ ǢI~=&j*M ɠL2nCs{UO>yjupryč+(Iy+)*F.i&0 `]xr3G}ܿfy([ģ6?^J۴T;g;c>r6Pp7Y(x_me(<c,?heq1fApxf&c% ǖkOhl/l)H̍ f0"SI3VqߜJզ%bf URrԂY?4/%DmٳW_7ƵV$;|Z*TOB'?M?'_|ﲔͿHm{,mP ]g>~hǮM/.N$iۘN C;(./o3C'!_62))Fp軼9AR3`Vxot ӵZ|Zn$>xgOYfPb" ,BQ)"er. <,{o XhIO .պ#Zr$@AzC=k5js D;ں0v R DmY'w?բbc l5]oo=m ~w}sb^$ K*Qַx25ޟe& ,frAtW;CQ3IV~eG'Gׯotyۧ}f&"P(Y(`rٻWQLjDLv~; ۽ Av]p٢3Qe/:d1=go0 4p`\k6gIeϟ>~|b9̏ίj V7qM'f=~ܟ,4laS+¥԰BL!@tѓqlƛ,j`1YZ@l{܄)Q( %QcТ$&(U4-?< 6 }Ho#2~ǃMәnFږ-y;$5cnZq U Hkt2%7q% NJwfw]f10NGw:a 2R9(7BJQ[Ѵ2Vr@hc /~1O"w.nd0:{zNBs?<%&#1>B~XKaEF`f5A7$ľw{GȠĄ@ZOWMS\_eP dU(cK*T jZQuP|;0Fh84Fn_:3Dd-A:sJɗׂdЦ#-qGzk5Jvl Z5}t,h1y(hkņr'꒚ և>~r]Z/omvbfhي#@ qK `$2C-[]x-|y2fŢ CTF-"9mP)4B4&[zcB|[W/޼z(ug0Gg -hCͶ79 ĘTTouuc37(a,w*w=86=<)/Zik/6?kǕ؝{1i3)CÕK.5]`Cn~B9:†zOR2 ϠƒlH?h:ᶥa#H~g??:栿wauX3oCOgI~6ښH?ؖT"i=G"bnΫjpLdnb3;ijSUۯ{(8[θY@5 =~w"!D0d_Lc6-t^]œv񠏱dW6)2ט!]]P66 ћ .ʻU//9@)W\0isdfbN vNt4{}/$&ۙYSYJ#ίhSurܿkeZ]'MGu)*~޷颟yU.WuP&/o#5oP)۵},l$0L N]vF<<$j,u4=UYK޿N&":==mOۑ|$W8 YPrQPƒVBxI4}eJDirM{q0/' fL")oQafʑϞ_3zU%"q-(YV}VDn\J˥>Fl("ƔJ>==Ř*hb{qqٍxn(!g}nw*j"T5ie?1`ySd&Fhl|Pi,ࣥbc! #A@Ѓp$&3x.(™y=c^ CtX 'cОisj q #bqD QBnB(,`Lg?e}*xrVUh!b&U/ &;o|_=84 EcEY$HMr0yՕV4Fh7o.v16b@jA"i{wMg|*m].y9#ByHIDU8T-'M6;2'?<n 4]rM!'拃on-֬82a.b{ӽ0ք2auѽUuscnn`c5dZ&bR@SsѰCnbhB3{kiih nOĝA !&y,''vWK/SJ'1ދmCq3 }PEz;crKo `"Sb0v2(A N̪Ib,UUQę/߼ HM{ ՠi.9BX秩gܴ?ܕޮw\*%@a ՇaREskEe,jE{,A&-t&E`5"KKSR$rMz2m7kRMLFyjS˟94Vۛ-SM$P*,UOY bTdvt( Rx'/ο9_o!OրG#Coz=_p7%qHMmJqG/uz`,:+޼Dz;f~}kDF.Y,.&,Ψ f wзПF-@fzͭfeƖ񶻸ދ\@*_wss~Q4 \Qh8FNrjB-d jٝ*V(N=mbRXٙylSlL6ɃlĊG.>8E/"MhdVIjw. [f ]ov].wNE#`&z} Y7 tdF߫cOߛZ@{ ʢb& VMgBǙteLV F^{<^|7P 'F0 ND K1kԧ_M.sylpҡk}שi7Z&+x:$tOǣ*x,]hN[a!0}߃ٹ  {N7kkAL>H׊ M=-Qzbprf&@a<y3',40bih?'?R&4 螼1e^ FTiNWt)i+g: y_-W2 4Nm۶YLLuGݻ`(yr2~GVȰےiotL]8U *د-tה,$K̛_,~ Ջ/QH70~=w[SydP"Zz]o}ܙﹰ;v E*rTkfhPP q|)O>MlTM(:"֩iE<[OH7IH!r3oA;.f0 AX@6Ƕ}g#=}͋C_X,z#,FUGń"+m7&8JyjٔSd8_=#ujnz= GCh}֕m^,3Pd|I!#ͧMߨ:q Y!E 넾"ЬZV5 Je"O}56\[C!XؼX_~vc%lwmEԁ4HӚ'Cc3oaSԋ%UgIy8 %3|=K΄cJM3~>o6"<Ϗ4Mmh~UmY"BYW?QL\N,%2RO]OzsyqmJUt}ߗ5tXC\LJr\v۱hLz~ 0Ȑ< D}sKo=Ȋ`R3Q&+`u(dܹҳk#d%1W!01E6_UӬ1Rl0Qϳ7+>31S8rْ adJZ޾!Ю?//}ك_=6踗 `ISblx.qNj4ݝv Bق̖j{uz#WRJPJQSA۷*)LQsǩ 9{:1p,rJ3[4 IDҏ|)o{x  Eo!Gus.qdbUH` 6Ous3Mi^wff ]T'x`Qi6⫯OՕ\DXU =ikġsݐB}GJEFڶ?ypgGm)4 `n{={OXe )=v}i!blӓY pP5A'O&%^ZOS{{?8k,2dԈeVsYAf)ZFIQ"S"qx!ir{H *8+`D]۷eAX.?&*LϞ,m6yk~PѻWE[Kk~|kU^k@b5p]Mvw-O@,[&!P>?mnW0b$YFi4˶27w]ۍp:Nv zׅWbv l~G^9{ fNַDhꡲ( XW_]/W{y +LGj0i.R'>D>)vլd^wےu<|,єCHt?}?<Ͳu~kG"dv$eӤªx{=`8}=6q`ќL)1Zb2IUW˓e@,,]֌@!7h10k/]lg_t.0GvС;2S<ޜf ЫÏHv䵺w+z#!8SE RqNЌR`(d4C0tI8y*ݺ8҃LGӈ|(ACCy]a:mbGj'>%!"&xqq{nZI.(sp}}=;Iص?Aw6|A#~nnD]m׫unh$4{ Ѿ5h'"zl{ԥ˳+{f{4]I UhY+tU[IÂ=⪈rJViF 6k ooo/o_%,xL) @|dƥdd泇gd,B=DDF-l4 %{'n펠[ft; Z-!ߧ~ulj8ةnW7Lꇏ5Y;S݉f%")ÒfRyd/q2%vWG/sʖn3Vߥy7)c]9a/:@iT|@48¯i1luvu%i5Lλ2C>ua" hFW/oGިg(zQfweÌC?L/_^T?ŋ:$~?y$f!34"_$R$0,[BHgB`2G:ZćjEeiG}`(rYN%cޯ#E^ ɻ`35O776g@WI&N^#FrR(dZ_îvWXyf4޾!+)R 0ˠ,9l9(< \WF4Z5O|B<1~\om .Ѳ6U0M@n/ 8@vЄ%_3ķ_Lۼ^I/o@,Z^o6J4r#\vtôב2!s 9Hr ]Po5j'?gZ|.SR}sT$nv]{˦WWM]j*Q>{זAa}ֻͬ\^ >{ rv ? IZ m,z.}9[1x#r>Q? ի|:0~PF^AFf5,۰ 黦& 6U^NlR99=MU3i? !Kp_b8C7\~{a$gRhQu(KIrA7,F^}>.0Nc+@D"RW.PB3RRS(\ \xb̨w=/󵲩 2F=e#Y76 +$`>Qԏ@yyV/,:P$`=c4M6.M=mʧQɲW{[8ʼnom;}oyphpYx-zM`aUU}чO_ٳgDӏ? bÞJxHU5dNJ VCwgin`NM#}9ڥzq޿xcvX_}s|@d`փ2lQNS 瓿IhԼ[ğ,4VG 0]8p?znՁVm *GO~׋_|W_3LYJ$M19Ww$=̒-/WNr14G{ ~g;y+Ys%kU;̵MhZVMl "7'>^>9̔,nnmۧ)zp~5P5>{彊{ݳ!=t+؁z0Rj6C. 87lLyGǞ;14)io9uݐﴻ+!1?GO^_^ ]CO-4y 0D4XXp\HTD&nj{7~R3Of^@GǺBE}wuHDd0ƁI Wb-8R7=l8L)Lsq8yvz9e@uߠ)Hz$+׻8Y߭W]=# Y$(#L?6S2,0!n#6QH\z}/~/AZ?? (F1t`,_5/>nGe?qfZ&(oy2hv6ﶛݵ~z0,@ K+22co]w Qѣ><ط}Gm[% `0wn  a*W$d {,nEW$%=9E?~ᇟz//<?ͷU)Uk-t0eBayuqq;S8a> ;{a-kLTj)#4l@>wGSX&@X:0AȱNg5LUȆ~(#S#8w: I< c3!&pE u[?x#R}'_}Df^6J_|nri(‘{EXC#}e?R?ONNN?~LSI) {{VǙ{06뜳d5QskdjQj6+zqXt1[VMMh~Ż}ȱpY⯄欉hdjYL@gN{OW/_;_#L<0p|U?=Pcw=^^1ӋaNOOXuUD fL}ED:&Vߢ"f^O"-lwUUpV- v`0]y=G{i˲0s<}ݫNW{׭s;˨PlwOuGA7=ڮۡ #"IU=ZL!*&8xىRU=1*QW~1D/ʶbrj\H#8} '!M?HDdL1rsOڶmˋvϐ,;e&J0;|DMO'AM(G6k^c`QT 6Sʍ6-I`"'"20ڕd0wM|6\=?mPH}q&_u > -{hNQݓC%qRPsxi8'jMGb]3?e*+"SHtXP(<ˋO:r>23VذW$b 5}сj$6w$fBŒK2q;ESX)fHcmb( #P|/FƪILU'>MNbJy3 k7e\foNm>{ô8*Qr[#c 0RǒJ,} %XGP2Nd\3M?q[I `f>[,i3gf*$z/:CpmbjIBf\ML`%N"3@] w;&xnV|"-V!k!{ab"ĨD\t>@ %?ASƓggD8,"JDsp {ѣ*܃tdK@UUe,Y ?KD(@4MƠY Gd|I7lDH5jqwRe2>駩vr2\_^ ]ԯbSTǿ/^C:':kac#La N `Dl2kdnnؗ?D /VkЅhMSe`B|ܭDYSDK&N f"oVWЦZ晣-HnW["3ՏbSmC7+"{}18 T!$ U ɐ#Q`Nxjs]̑׿_|ݯ/"8"|槪&b^8X8-?: ٠68np⚢(s,8Q @ۻvwt\n?0s3 :F9<*@%<ͫIiyW(v 7LM\-~b'IF~<'Gr;N8DəmKC<ҽ_vAJ٢"Q2 PWDB2 [\&9 "@e'''~vwHa"%# Wz,",JLKulcwٶwjkG]=`٭,Ap1 fqtq1H1M1{f6L< = 8t/Q#"([PfцIJ7,Ta~2oUVSI''ӡڊĞ 7q PG{|Tr(s}8'}77cJ7W'"6Ygo$v̈́7ÒT fi6`X%dۇgR`ng G楔a e-&H CKmVq=5rT6ϹICl[ٌ_͓iK*&D6t%SX0vr2մ&mo< R~/.V Ւ|~{%S#%F!!"2tU*"']Kjg=חkiQP-K3?xWOY J6hKL$)Sgx}̱GRMBM)D`ĉ)ʈc̫*(2D&'RxNP7= ]~vCJs/QdY% rٌy51Y47f8̓Rlovee^aQ l_^gEώĆ9Ǜ{*&R"[H &NA7`0(x$w ѹ2UdUzcJbj*"jj* NgZwu&D .ֵM[z+6jV{w'7nYb暡 zMmh  F:R-q"~|2ǂ`l$vZBiID ۱5RٍfLUdDH6bD@ik2@iSruI=jiR"eA *C7"qeW&lciLy7V|o>S5gx ?:|F>d+>|%hO4u0C{}]M)(|mR%9ljŨ9]]tFI8ORq O&E wԧaOƬQx&MJyFp}c@ MɘYI 0E9! .c C,7T%a|RZܑ>GQn bLx׆qy ɺUwPvk?gf![ \ѐevög U*^׻/\eI=.˼%26@uv =0򑐺t]FɌ< bhT()P!"SJD!,]nMvv`4I({.mNphg8&V:>gYo:#SR({u9cX=$#ER:h[J)Z")}'Z]ߐ"o!3 gf LQ)ݏMP|$6}@,iNIU67[%ɒ!Af2t~]-LhӝBZ#01oMx*'(fsM¯eV!tc}DD ;,80ik@`Ho~MO[j#bYI)S;8M: @XuLqi)rHwfy{:Ҵ-y+Vy@Ȅj6?݉}XVFEb*Z#dYLbu \ ~'0#F hjhL( &`_N@nb>}ykt,D:WԴ3$dBD69iiSe2 2,!˪[H az]} LJϿ&U+ cds#JQeN !#UUpRkȷ;Tiv?|O)8u35R|O3!EUnkފpTMv+b2W1L,e &2v}&|~s0awQ07ٗg"(ZbB{Qj[໫AdEl:pM1%3ʦPp4A T9@D߶%l:8+Gc5$Ӥ'^c2O+>jx5kق&,ک>BベAL" Ϙ^ ¬Vvbmg9A dY6(ka^LD0-O+oe~5+!iycC bfE3fi]-+;dԄG1װLbC8ӏwHԄ-&Yl9n[5s*E~9Y#RUBX:dۄPt9[֒`2}ucxyDBŰ\i+,HX#q4YB&aPד5盚acJKCEr1=?gjfm̈́hw,y70փ[]2*"Q;g>:@֛zIАLtN)s";@ MSO*˺[ݷjh 'S"(ZZXUtu w9!dH k:`+5cGH+֫;HT#T4u ƅ>wP#8P34<aa j#sfgdhi޺cqJ/#H{MOiO^{0@%&4uwNSM^}^nЃPS->3MMԕKcC8A c- Er;0 ~b{8++ޖT~7ܾˋkw7(»AYbnn`LH!l@56 mH5(ӯM_MRbT9!1Mԡ{ 4IzxyJװycwd?Ϙ !ᑞ|2\ 6.MEГ1c.|$%S IS%[ኹl+qVBu{aJǿ߲8" eS Io3>-ISԘQ.ْU^D353({n^L^V_NS2@̈́@Z,\,y?}LF( c+ATU 3~j= ݠt L{ 7,zHlKc@xpM`XUz ){Q?%놙UȀ885s'b* HҎ_;@b\=ќXm[yHiĭ?r߮NU@]R;$c8o-BST1N0v o(pC?fwn޴ǒ,;f%\+vNġ gUhf Yֈ쥪:{~edV&)ܮ][΂=doXAzK9zwDc6/'QWqpNN#2i[lF/[`7Nm"^0q`@J}0f"CMUzP2"UIBD ̀ oެ>}uO{W)T]ڬgTgTK&ƸNB0 RC-K߷Gm^йȴ'2s9gG/I}XpU6[6h)cc?X4VgZn*Y%9s u@B\Ū+O,+4.@'ojʒW5$P4itj۟wzJ!0l8'gVszͻnGfZnp3v\rXJ(R6~*@嶺դGYNuv$kI0wyA['Uuq+{]RE}fݝMՎ^#s-"8:T+u~Q> '^ɁbjݼL$!jw 9MAM8:tq_VSVO>HId䚂N#p]sf򂒇)=wc,<|?]JW:׷][gfG:B7` 0WНa(9ykzqe,Y)e î$DL JxJb׃qAÐ5*Ee}I}e*u0:RS4dp:<,L~vvݽڗv,Qy» aU9I:c}uɘ(]-UJǃkEqSY#6*}S%"Q;ר&Kseb=c6>P,*&8i Yg7XwYKI($1 Hɪnw21Q˽wzb8JDS1zT*4kBz./3G]iԯ> AdPCU0^bG%o]nI)duD"a@ĩQN@dB'vHڹ e<Ⱥƈ?XV+dP4u}AP=p os33+ ^{?PH!k0MH}lWByA sJRT?t jvz#P2VV$G,-}u("u1Zm@ >L]^%0B@5IOBk^M]LTS:܈wЗY#G>1ӵռ>ۼi? 1y?j7FCS 3]H.>XrzRj^ {GTI&x |MD[icMx[h>Rn?0Y[k,uDUx}hַrwKڠ?TSLMU q.Lr)am"1GU]N*g]tssţ`ChB 9yI@EΦ۟5JPTu#CY\KI)/B YQw4J(ȅz٘E!">TW{@ FN Gm>i|duV|I::i)oF]LۃVg.qq+ k ^U~4`Ns8D*3QkORdʘHafkBB͎Mѧp)i>TSi'K:u}9lt3Cj[prM@N~B8x?ڤ** ʾ&YUۮuU׊}5+%ܾEouW "4BM!nѰ_~EɽN'ma4汸q4˹ -*c` lg̷FeU_')PKQ{u"iQA=Xnl&5ALW[mۀO\6¿RѯDok޳ jؕaiC,>un`W, rY#t|_ XeZ ~6N:Utj:FTA- tuRDk{ȰLFJwf^n2ij18jG}pD5hgpzB<b!]<yLkUfV>5tԑᠶ"VxTF% :[ȆA[TB"7ґTH=Ϳo6ޛ4_Պ?{t= {eӹlPүyGBoYI ]( .c1M u^|&`T@Y\(0CaqRFM]IfaMep"b]j)kY+>)kgY$lk/:?q o&(~jjD>X>J^de ac`_AX"fX EI"wIFy'>FNZB%En{˸uq!?WW6 Wl5,!0 Op"@,qTՖ)TLrBmnzyXh0H&Yn} ws8̪eLɫN>/ԫrWۋ/[|O2J?{ׯ@Vqa_W&e9HtF1f bW?*ɈO>eGZ2ksObd𐳚GN~K7G&%1=⨇2=ᚩWŝ +8F84GV gg>_қzpWЯG/"a7r+ǯɴc2s=fz4W%3":݄">V7B 0_/?9R`))jK29;Hx^'Нu$n($ë-D"H鰷ڼ}=Vɣ( %9._^:ɲ90[$%"ZveYƾ@ Y >"t?$Y$QL7?۔NwkWr蠖Яv37.wK_ꪠ~}?~Vo|ojeݴ3?\{폇Lshۼ=lfW_Px^vݿ+ï l2l˪Sh-UWaJ[𪨃IYlSqeQ}7OOM=å1OiEJMU!0(B #PVn98' XSIcqY?Rt,ɲ/u:L>Tu]ٔR鸽U'4B$+:jA2nٵTUIU4CE] ³c݊!Ӑ_"97P]vG@Zӭݿi+C)R%[E\+|~ޭW7eWUeF_Kd-}?ˏ\ur5A^kW88gjU/8Oq{ٕRSe[]Ed=PԃpRr*'~/Ia&XCJ{/w# Jn*jfY{}WRJ4'(' 436$qfΊCiw;uO4ag W޾iEXyzU[?>h8bB_wi1z. %!DFUCn4nUm:C=fۄ_)N\3"+ԃ;Dꑦ< 0+MXF, h9}[3Q¥2Fݶ4>wlb-bwPg 6+lF>hb`KgÕ9q@ą^1\c){H,3F~(^=*!F6+ #Ֆ')C^J`%¦!PK~ GqʖijiҼOYqT7oni6֙`~*o/ױ~sF@ c|WWdA%Yb,*QP|Sr({hJbxT-R#\]] T`ǦAY~Ϻų+~R!'hU9$WDh>keKLp3XZuvV)|5e1f6n.5Aru-[:QC%E.'qG2Y8_q9FX G.4y9շs.m'stqӥTRU7bK4l~8(|O4K{@?Uyja^z(w@- !Q1UEoA ^ݲMNltR pmvxGҤM J+K5ۡ6EyrZ o0␯R󲟦oarwԆȤB b eXc\(^_yuq_o>Ssna4CIV݀˳XVB5"ylBSr"0R{NTǻ2 =F~ڥnHXR@fsNyc 77U8-)g@F73 J(F/]yC)D 0FF^E}Rӝ`#J:Pcd"(J)K@")LJZn=8꡾ۀ7A\Hݥ "?< Vc>ӥW9Z1cI.E9YYɛ9eVWk{Z{{Y*Y' K]m&{{_J5m&[a+I2NjV䤳?^u8ŏ$(lbp^dK0gJ)W7.rҩVANtH<,$.Y\#g|Xw])$(^4C ej½-0^>6zx0_lצRѕoЎmH}zu),'j8ԘNV&mKb 54\Ӌ xVKSlt˯'i 8Zh^9d,%Cn[(!qjH{tuf˕f7X ?jUmX 6e7oEhiR`>5o|cl*{nؽڕ$G;SXh.Z1r9N EQsPz4u "EXg$+w Zd6pժL" (pBT~pfesyyn&w@onWeWfu$ź'U7PK@qǚV׷1kɻOcdR'}{)c]Шx∓?dD)D^YQ(Ru[ZC9~'IVUF0ĦlRd"/Uc{iq<P&M5 ӣ/REOɻza8GsV"Oo#ramD(2Sn˔ ̮oNeR_DA `k53zBBD6MKS[pYɾMS 0(!Uy}. Vk] |fE&Aյn߲2DٗYuߍvo}dt I'3JUYio_~N!WgLym";(O?l֎GTA) cʽ{7sRVAݡ1wnߩ!k]Iymx? :ե>suʜaھq2r AX,ejjpiE!j +Ul n4XFM-*yMir˥ZTiK|fg\>;yzʗ_)œH}ڼsPs1 BgzIв/6to$Eq~~651.kn$Y ZJ!Xq8 P;6`%呍4vG Vcۀg/\}=o5sJ6QZZGSU@h'Nm⚄H$*RE]oO+1cO-ZW]-½pGyJs.7Fzj/ewVQ Jr:~ a;Yq\ `,[R@soAy;6w*y>ݶN:q σ.R k+JwS I0YE&-G./$w?ps_/8c{z''u>:ƫanzf%lWSH{|e8ܞ+cm+6g)_x{xpϜFτHuіl񹼟bܗbgh 66،:qĠesl>|UVt7ET [oO7^lN3Wΰyn)n}vǥ嗏HUq׏Eq:ksFR߸H"MوTTxZefR2π沬EGf=Xы筈VXN@_ 4%qVXP ge@vuGD O?gxq+CjX ql{Y;. A~d]k`8k+Gױ'0" 1БSF:~+h:47*rz#QfdkWzww%à, dark red #eeeeee dark red dark green white upper white #8faec8 #eeeeee #eeeeee white #7b96ac dark green white white #8faec8 #eeeeee #eeeeee white #7b96ac dark green white upper white #8faec8 #eeeeee #eeeeee white #7b96ac dark green white white #8faec8 #eeeeee #eeeeee white #7b96ac bless-0.6.3/data/bless-binary-ascii.layout000066400000000000000000000015461374060072200204670ustar00rootroot00000000000000 dark red white dark red white dark green white dark green white bless-0.6.3/data/bless-courier.ttf000066400000000000000000001211601374060072200170400ustar00rootroot00000000000000pFFTMuNUTGDEF2GPOSlt4 GSUB>ތXOS/2(jxVcmapgaspglyff?\heada6hhea"4$hmtxNIHlocaN maxpH'X name1 dpost^ ĜC_< IIZXQ@X1 @xPfEd  8ZI @XXXNb-boB[nhRTJ[f_kQ6@6x -@"9H0'd;<;+G+-c+! T5]sI;G5Ja/eD$e"44Kai hVo`K | OZ B$ePx @9999dddd"+++++v+ GA;;;;;;!GJJJJeeee4"44444B4   ; ; ;@G@G@G@G"559J9J9J9J0/0/0/0''dededede/v;D<$%;e;e;e;e;e""","+4+4 -K-K-Kcacacaca+i+^+j      ThThTh/:+V+)Qy.Ea4X[[ r.0p B 4QQVVW@66IQ{,f(fS=ZN3Z+VnIn.$;U 1e0~"+HMs~    " & 0 : < > D p {  !"!&!^!!!"""")"<"H"a"e###!%%% %%%%%$%,%4%<%l%%%%%%%%%%%%&<&@&B&`&c&f&k $.JPx    & 0 9 < > D p t } !"!&![!!!"""")"<"H"`"d### %%% %%%%%$%,%4%<%P%%%%%%%%%%%%&:&@&B&`&c&e&j>n^4210-$EB߿c\YP>3~qb܄܃zwtqng`YR?,)&# ۂ~a_^[   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`aPpcdhRvnjgti|wq~fuCkzbmv2{l{S  GHMNJK+YUVQwLOT4:o678x;952bbpRh&fz">Pdx:z\:^ L  > f  L  J $ : ~ 0 ` .V~^J 2x@Nn*fz,z ".:FR&2fr~(4@|Z HT`lx ,8lx<HT`lxZZfr 8ht6  : j v !!!*!j!!!!","8"D"P"\"""##^#######$j$$$%4%t%%%%%%&&&&*&6&B&N&Z&&&&'' ''$'0'j'v'''''((.(B(\((()4)n))* *0*~********++&+D+V+++,,6,D,T,r,,,- -D-x-----../*/~/0Z0011.1Z112H2v22223$3N333344.4>4`44444444555,5D5X5l55555566686N6d6~666677 787N7n777788,8:8H8V8d8r8::T:`:n:z:::::;L;;<.>`>??>?R???@@N@Z@@AAAADAdAvAAAB8BFBbq;#2"&546V.)'(:((;z/$$$$33#3#_ J_ J3N 33733#3##7##7#537#53#3/ / ^a kn / / ^b lo AAAAAbx:BL3.'#5&'&#"#6'35.5467533265>54./ .'!#5_J07 // 3%#(8WH0&k%J.,)#7[/?  ,=K Um!1 !5$>Mhh ڿN! H +!  -f  *.$2#"&547"32654&2#"&546"3264&'PMN@AL'00')//AMN@?NMA)/0('0/ jSfRR32%4"#44#"4RhQQ43S/5D43F4//b,53#3#'#"&54674'.54632327&#"6'32_<,Kr)?KBO@7#G:(' .=2%! 8n!//,4/C7@/"2>4.N?(%P:/G'(T; 9T; m3=LB$9bf<*@YN,$BL=35ZR^SZ55ZS^SYhm 733!53h uX//JRm%3!567>54&#"#5632!/zh"Z0(-4JkJt"e5i";%@E +AYhQ96&PTm*?32654.'&527654&#"'>32#".T`F;X"%<@ 4D31M2M+DfM)CsV;+#,.I? 3  /#?1Sf Jm3#3!535!53#ZZZmU0c//c:Uq[^!!632#"&'732654&#"'~NC6Yl.V91O<YMNRREF?^0qS!B?(-(TB?X0fs*"&632#".54>7632654&#".VO?- 8YLceL!B?'&J2I[13HD5 0,m27nPKtNMq;qK8]LIa\TL@;U0_^!#!#_:1^//\km!,.5462"&546"32654&"2654&;ii.,23ff8?AH83MN2AJQtQK5L8D``D+QW*@ll@/TK+0LE78>N13JJ31NQm*52>7'#"&54632.#"32>Q.VO?- 8YLceL!B?'&J2I[13HD5 0,27nPKsOMq;qK8]LI\TL@;U0y 2"&5462"&546,/0:00/0:00&<&%&&<&%&y %3#2"&546gmGw/0:00&<&%&6Y"- (}Y-@!!!!@((226T" '-J(}-x<'5>32#567>54&#"2"&54x;?(Zf#@0"1 3@K4=C:()8)f`D)?& ^fc*MC(77g0i0 N333#53'!3#53# q3f98f5,qq3////- 3,!2#!53#!#32>54.#32>54&-a^Or'@@DSS.@ #:}3"f3T=S)"j)D" /$!, &;8@RD %#"&6323273&'&#"321!ysO1  % / (Y`t /N1o$t+ 0Ze@ ;f!AF6""'332+53#3#327654'."K\&>S=OOzuf0C/H3/MwO:/+/CaA)93!#'!353#5#!73!53#9. ..*.UU3IH㉸/H"3!#'!353#5#3!53#H- ..QQ3IH//0BD+3.#"3275#53##".54632260+!=(Yysm=\0tYIp>zH5 > ,%+02 ڊ //16Zc5{+ '233#!5#53#3#535!3#53#'KKLLKKKK3///+////d3 !#3!53#dp3/+//;C3!##"/332>5#vL%Py 11E$1 3/q, 8a*+6# 8<L33#7#53#3#&'.'3#53#7654&'&Ge/&0) #I_8QQb97.>*$%3R.*M // !>&8 +-D,7#"'&#"'67.54632'#2632322654&#":+6-!.*6Tdjn54'&-5:#JO$kX}">$HYRR{];"*3 F$5\"/Ja%// - 7cDE3&'&#"#"'&#"#654'32654.'.5463232676- -(WHO9$?;>|QR7- - (K+")G*!sTH4>'!.I;#=J, , *JQY. !+.T<5F.%9&Ff) +-3!'#3!53#'<0yy03+//A33#32765#53##"'&5#f"dh fH$X=s7"H3/['G?$\$//v2-N1|R33##53###^f?>E3/4//V33#333#53#####e8"~:f.K22F/3/\l//l!733#7#53#3#53'3#537'#4RL34Zj353/////// 833#7#53#3!535# LN?vw?3///֫//*T3 !!53!5!#[E/PY/3)%/Ւ53#3#5~~2x2]uw+9s##53#53#~~^22I3#3#,@J@g!!0HK2vj3#kM4js;&"03#5#"&54>3254.#"'6325&#"32Y]bGZ-W;JB 1"K`lS0E!2?C.E @*b(/HVV701 #*-- 3P #%7 u!73632#".'#533264&#"Ch]~^%=.P\eJH_`HIel X]W#M/GffffG%&'.#"327#"&54>323276. .8%[c_[Zzqg8^;S@< '$knU&aa)PC)5 5Es73#5##"&54632354&#"26U>k]V0`[NDdcd`/JT[a}.( Bl`bbJ/%#"&54632!32%!.#"stkjyh&O6TdYS.I(e,G_`zM "29$8]!3-aq354>32&#"3#3!53#ah B4>V@L"(hh8$./2$5///D/c) ,3#+52>=##"&5463234&#"326Qd?34B V:Z|V&P^A@b_CEZ/`[/0":6~VZz'"H\\ED_`?u7>323#5354&#"3#53'E!DPTU4,KbOT]i [J//6AP//e 33!53#753ŭq}H//PwwDi!#"'732>5#753U1 &='6Q A>&6Hz,&0/Pww$3u775#53#3#53&'#53$8NGT@4~8S_h z//t[//>u+/ec 73!53kڮrU// W1376326323#4.#"3#4.#"3#53#r #3 66<2  9k 3/>p 3-DDD# #!?17/*B/&8//P"73>323#5354&#"3#53#" $F"DQPV6,HeTRR8\I//7@P//P4$ 74632#"&632654&#"4tvvt6hZ[gg[Z`klJKkc$"33632#"'#3!53#32654&#">nb}UiERRpBEdYOMfGTZaV//RafKDie4cE"#3!535##"&54632354&#"326ERREiU}bn>fMOYdEBp///VaZTGFeiDKfaK83>32&5.#"3!53#S:="/5 >:|td+' 2//PaI.#"#"'&#"#654'732>54.'&54632327>- , @19C ;$' 0"uJIJ ,, <'*5!.''cND/ /'*&*  ,CH**"E&& y6H i333#327#"'.=#532 *E|~PO- DD3/.4-9-?>/ ,3327#533#5#".=# dSNVQMP-@ RW//7E!7:!C3##53###QOJ/J/E//V3#333#53## ##SXb#cZT'p4_]1q+/3//>3#7#53#3#53'3#537'#)=}}:=?GF>@/}}//////gM3##53#3!537#ED:YԚM=/0////dh !!53!5!#r~/xA/+\/PY3"3"'.54767654'5654'&54&  )9', UU 0 4## & & ##4 0 ?( /6 39-L GG#G5Zm352>54/&54>7.54?654.#52&  )9', UU _0 4## & & ##4 0 ?( /739-L V#"'&#"'>23274"6EFF$!3:L?/&&_','"$ Cvq3"&5462.)'(:((z$$$$od.9>7"#5.'&5467532326565&'&L.651><189#[Q12/ /#"\"1 " ) !"4?Im 6-B""#+5,$`d:3&546323273654'&#"3#632327#"'&#"'654'#`[jI5= -- *;=G 5&!.(#24;(1.C!T iSE(E_ 6:  F,#K/(!\N)$4'+Vj'&K= %%'#"''7&547'76327&4&#"2R#Q.?=0Q#R##R#Q/>;2Q#R$/J:;HHtP"P%%P"P31A2Q!P%%P!Q22AjNO45O 8Q$%3!535#535#535'#53#7#53#3#3Gww=LL<\//\/:/ //// /:/GG##G555uu|3+;#5#"+533264/.5467&54763'>4&/sJ$',J?/u0)'$0!.A7 *"3V:!j*9 3:a<g- #<)7c i$$m53353H:Hllll ND%/#&'&#"32>7#"&54632'2"&546"2654:;CD7. L.HX[R8DxДДa2 P:([+Q.*#2>1$"X#$*-} "Pv$#,$-yI$O '%'9!¾ ¿$$$$Z!#5!Z2 ND&/:E5327#"&'.+#5267>=4'&3254#"72"&546"2654&tL ($! 6dR 6xwhғUDI""*5dpE@ywwy&ihhiP!!TP2;m462"'3264&"YYY":()99R9Z[~Y(:9R99B@ 33##5#53!!22,@222m3#5767>54&#"#56323o' F*2,(*,C1D*DEYa'>'.'* /7B/$:??m#'632#"/732654+567654&#"@+-<&8E6&9>&"-Q,$!&!"*7)/"<2@%* D(  j#75Yjss$d2!332>=#533#5##"&'###$ %>'RS1U*@2R...!=)//ET- e3*3#53#3#53.54>;54tR~>853 $D4 A.$5 '<ys 2#"&54767>54&#"#56323hLMI " ?+!)&+?1@)6>C+&& XAV_' ;$ *-6@0$@17]y59%5#73#3#535#57%'632#"/73264&567654&"%'s555CB?,-=(:F6!?<)$.,(,%:,.%2$$2( )7(0!=1@#)D&% !!KAxt'#"&54>7533275"&5462;?(Zf#@0"1 3@K4=B:()8)f`D)?& S=Oئuf0C/H@z///MwO://CaA)O&1:+-&2C+-&2t+-&24+-&2:+-&2iv| '77'' $$$$2##$$+-D$7'7&546327#"32654 &#"2"2GtYI'#,@q[6EZq.V[o%<A]v>18M{-hYm5c'cA&8CA&8tA&84A&8i 8&<tG3(73#53#53#32+#32>7654&'&qQQq7_M!)* #I_7bb97.>*$%/////3 J,-O ' !>&8 Aq)734632#"'532654'5654&#"#AL_C@N/$3WMC0<6+Dʈ0,-A~/O_S<+E &C)Fb!4#=>. c)5>FE;&j&DC;&j&Dt;&m&D4;&l&D:;&m&Di;&&D8!8+6@%#327#"'#"&5463254&"'632>325&#"3273.#"3 6/BN7N3KJ9CUK CXLQ61/ 4 1", <3s/)(!07*+JKN59] #95,(#/dx A%!2IO('Gp%8#"'73254#"7.546322?.'&#"327J   T}rH: . . )JZd_[Zz=a )%6~dY) )< '("!kGHmU&--J/j&HCJ/j&HtJ/m&H4J/m&Hiej&Cej&tem&4em&i4$%'7&'77#"&546327.3264&#" 4+2G(?;)+'luaQ8!CiY[ghZY8RL! 1C>q_i+>mnn"7l&Q:4$j&RC4$j&Rt4$m&R44$l&R:4$m&RiBN 2"&54!!2"&46$&,$2n&&4$+7'7&546327#"32654.#".'.6t`81&.7q\1 [g  [g .%.AU^-2&.@Y`Z lJA mIA ,j&XC ,j&Xt ,m&X4 ,m&XigMj&\t c$u"3632#"'#3!53532654&#";qb}UiERYpBEdYOMfuTZaV///rRafKDiegMm&\i N&$o;&P&Do N&$6;&p&D6 N3$'#"&5475#53'!3#53#533#326 $ !#Gf98f533%  mqq(5""/////  ;&3A#"&5475#5#"&54>3254.#"'6323#326'5&#"32 !#]bGZ-W;JB 1"K`lS0E!Y2; H?C.E @*b(5""HVV701 #*-- 3/P #%7@R&&tG%j&Ft@R&&4G%o&F4@R&&7G%m&F7@R&&5G%t&F5"'&'55E&G55Es'73#3#5##"&5463235#5354&#"26UUU>k]V0`[NDdcd`k/V/JT[a}.(}/5 Bl`bb9&(oJ/P&Ho9&(7J/m&H793*#"&5475!53#5!#'!353#5#!73#326 !#UU. ..*.5%  (5""//IH㉸ J/(1#"&547.54632!327326!.#" !Ol-kjyh 'E,U_P%  dYS.I((5"Ga9`zM "'0%C,5  28]!3-9&(5J/t&H50B&*4/c)m&J40B&*6/c)p&J60B&*7/c)m&J70oBD?#"'7324&'7.546322673.#"3275#53#P#$+C8."#%7W5#zH5 0+!=(Xzsm=\0j, /+=LI${+ #J+02 tl //,'2&+4?&K4'23#'!5#53#3#3#535!3#53#535#53#!!KLLLLKKKKKKKG//G/////_/G//vT?u%3#>323#5354&#"3#53#535'7&E"ASTU3-N_OTaa]/oUN//6@N///:/ d&,:el&:d&,oeP&od3#"&5475#53#5!#3#326z !#;  (5""///+/ e#"&5475#53#533#32653z !#ŭ;  bI(5""/P// Swwd&,7e 33!53#ŭq//P/93 &3#3#53#%3##"/33265#/XXWW6@%H*3$b3/+////!$=#&@1F$ K`8vi #'3#53#7533#"'732>5#753mWH% &='2U ;C&6Z0HR/Pwwkz,&10Pww;C&-4dDim!#"'732>5#73''U1 &='6Q A>&6uL] e\ z,&0/P^BB$o3u/775#53#3#53&'#53#"'7324&'7$8NGT@4~8S_#$*D8/"#%h z//t[//>u+/, >%3?5#53#3#53&'#53#538OET?4~8Rb//vY//>u+/P/;)&/te&Ot;o)3!!#"'7324&'7#53#5!#!73K"'#*D8/!#$dd{/  , >///+eoc!#"'7324&'7#53'73E#$*D8."#%ڮ, >/ ./;)&/5e&O5;)3 !#!73!53#2#"&46;{/ dd2////3/+/Շ%%&<%e:c 73!532"&4kڮr`<./:0U// &$$>;)37!73!535'75#5!#ѿ/ dOdd{Am(|/.);//ec73!535'75'7Er`N(\//O)\ .O&1t"7j&QtoO3*33#53###3#53##"'7324&'7pAYqNN2#$+C60"#%3//+//, >"o723>323#5354&#"3#53##"'7324&'7" $F"DQPV6,HeTRR##$*D8."#%8\I//7@P//P, >O&15"7t&Q5,w@!3632+532>54&#"3#53#,tVIH_=LL(4421i)TUU3CPdAzKS2,,4@7)//"u#3#53#53>32+532654&#"TRR $F"DQ`=CC478)E%;//P/8[HMS2F(9>+-&2o4$P&Ro+-&2;4$i&R;&3$!#'#353#5#373!".546#"3, A..A.Ik.`n*L03II䊹\z?zՈd'NG- 8%4=%#327#"'#".54>32>324.#"32734&#"2&%+HO4_*+^%8M:4= C#0C'4/$l2., &1H#+]].+9DnL8(*GV* =P& AX2*F7?Z C-A&5tK8j&Ut-oA3+@!23#&'.+3#53#!#32>54'&#"'7324&'7-5:#JO$kX}">$HYRR{];"*)#$+C60"#%3 F$5\"/Ja%// - 7, >Ko81!#"'7324&'7#53#53>32.#"3Z"'#+C8/"#%|t:="/5 >: , >/P/d+'2/-A&55K8t&U5c&6taj&Vtc&64am&V4coD\#"'7324&'7&'.#"#654'332654.'.54632327653.#"H#$+C8/"#%2'- - ?-KR1%")G*!sTH4- - B/DS9$?;>W , .  !+.T#4A2*9&Ff)  '!.I$<"G/ , )K54.'&546323267.#"D#$*D8/"#%.!( ,, <'+4"- cN>* - ,:'9C !> )":$_ , 1*"E&& y6H /'*"+  2$9Lc&65at&V5+o-3$!#"'7324&'7#53#'7!'#3;"$*D8."#%ty00y , >/+/io3.#"'7324&'7.=#53533#327Y"'#*D8/!#$%3 DD2 *E|p  , 28%"//.4-4+-&75^&W5\+-33#3!53#535#'7!'#E{y 10b////j3"3#327#"'.=#535#53533# (D}|SN- CCCC22/O ,4-9-?>O/?//A&8: ,l&X:A&8o ,P&XoA&86 ,p&X6A&88 ,&X8A&8; ,i&X;A37#"&547.545#53#32>5#53#32 !)A)Hf=,- fH-F5 (5"-#8//"'@$!+$//jY ,'#"&5475#".=#53327#533#32  !%MP-@ RdTMVQ2& (5"$5E!7:!/V// 8&<iT&=thj&]tT&=7hm&]7T&=5ht&]5(&#"3##"'732>5#5354>32"&+=9i($Dkk+T:"3,7*&1+2$6E*<&6%/c)j&Jtm3''M\ e[!m^BBt#'77TL] e\ ^ABp33274;#"'&.%MK'.)y]1pDDrF Pm53Hllx2"&46"264 @,,@,]  ,@,,@ "#"&5473327>l !?^*   (5"1   l#"'&#"'63232( 5!(' ( >"($$k (- 4Y"i#73#7b,bʂ,biqqqq:3 !#'!3#53#:. VTT3+//+-D !3353#5##4632#"32654&#"////ysuutYsZ[rr[ZyCCCC)}|ғhgV3!#'!!73!57'V/ 괺%.r34+-3#(#3#535.54675#5654UA_22`AUT?^3oxT3/*$:?D><$*//*$:?"Nq*/')5(3%3#&'.'#"&54632673'.#"32Bn 4;#QlmT-L2 /1C   R+P.:RR35'&'5"32654&&&0[]~.I7|MX^EH_]g/ 8>([X'O-Y:aEFacFH\y63.#"&32?#"&54675.5463232)02#14-!M5K! =AE>  N:V^?-*/TDU-?$$#%)0 2 2G6/= >#/C).+#3#53#3#53#5+SSHHRR///P//P/EP'#"&5467>3"32654&P{ad7-W1+KMegKGih2@Y\9f2lLKjiLNja327#"5#"563!28 4/Q>4-&1/M; 0/4d$(754>32'#5.54>7262>54&#"-* >,+Jls2/H* B/R7R(L317B*91 6"%Y`*1;/5B9'>;El,!X=!!XX=7=!!0H=7!=!!HH22d2@c3#73glG@@e33#hmG3e73#hmG@3#73#73glGgmG@[@33#73#hmGgmG3[73#73#hmGgmG3 33###537oo7pp31X1333#3##5#535#535nnnn5nnnn3////~"264UR;;R;~;R;;RAw $2#"&5462#"&54$2#"&54O6!"!3??f?>O6!!6!&3?@24>>O6!!6!oiQ54QQhR/4D55"!PjPQ43R/4D43FQ54QRfS/4"#45D(('!¿$#'7'#r; #2"&4#2"&4. :((:(Y. :((:);z/$4##4z/$$#4.*!!.20)}'(-&}ym2"&547"254r<-,@,Z7!$2+:;*4"!7-==((6%$''((m!?267'#"&54632"7.#"32"JA$(.??.8C)$*Q- $%7)8O E21C[K7#>4.'344**-'4^R\2+:z.2{pD36323#5354.#"3#535#ph88k5= 1888:)r// //U38m32+3#53#3#3267654'&33#327>3#"=#53%.#"2#"'#654'732654.'&54632'46,!be9PEEd:QT"((e-oo  ;!E!!A++ : O?%"**! g8$3&(90' //թ !#4,P ,iP,   8$' '?' V3-K*#52>=##'##52=4#537!#.+;#526=&#6=V n `^ ^ I[b ~ .3   !  $#;D+35335&'&5462353#5>54&" *?"NO">*8#$9qB&EqmmsE&Bqv%E,a|{a,F%vTy(37%47&5462"&632654&#"32654&#"733#53%'f5.A^A.5EdE0*)*0. !-/",gKMI7!$2+:;*4"!7-==:&&$'&&%+&& XATy(KO%47&5462"&632654&#"32654&#"'632#"/73264&567654&"%'f5.A^A.5EdE0*)*0. !-/",?,-=(:F6!?<)$.,(,%:,7!$2+:;*4"!7-==:&&$'&&% )7(0!=1@#)D&% !!KA Ty(DH%47&5462"&632654&#"32654&#"3#632#"/732654&#"'%'f5.A^A.5EdE0*)*0. !-/",Ь'5EH:,:;+*10%)'7!$2+:;*4"!7-==:&&$'&&%2&kE46E$.&%/ A Ty(15%47&5462"&632654&#"32654&#"3###%'f5.A^A.5EdE0*)*0. !-/",~u+x&7!$2+:;*4"!7-==:&&$'&&%2!G5nA>!#"'&'&546767>32>f( 0@ ?/  (82;3  6 <L!##"&54767632#"'E2;3  6 <( 0@ ?/  (F5!&54632#"&547( 0@ ?/  (2;3  6 <33632#"&'&'.546322;3  6 <3F( 0@ ?/  (B5!#"&'&'&546767>32!.546322"&54( !+: A-  (  )H 9; C #-  "3  :) .$ D _3632#"&'&'.54632#"&546767632#"AC #-  "3  :) .$ D ( !+: A-  ()  )H 9; _37632#"&'&'.54632#"&546767632#"3#AC #-  "3  :) .$ D ( !+: A-  ()  )H 9; 62>53!#"'&'&546767>32 2f( 0@ ?/  (8;3  6 <BH!5,H22  33!### / 0FI<2+ 4$#0632#".'#"&5463232>54&#"&'&#"32>,K,CF-G="*'4s 2'%/VK<5/DL;56=J' !?$ BQ)3!S2{QD3#54>7>32#54.'."2d623274"6EF!  $!3:L?/&&_ ','"$ CV;#"&"'65>3232?>#"&"'65>3232?>" !)&"! %KA/%" !)&"! %KA/%&%:'#D&%:'#DWG3#'7#537#5373d3>63|3A87`f9ze9f9m9@a !!!!!!@(((2226!"@  %!5}(/@--336!"@  '-!!J(}/@-A3I7 3!5'Io\8"Q!#44  I#4632#".'&#"VTY9* eip' 1{ VI3#".546323265TY9# Ikn  1X =!XHHP3H8X %#!PHP@HP =!#PHHX!!3PH H@P3!5H HX3!!H8HP#!5!3PHHHX %#!5!PHXHHX!!5!3PH HHX !!#!5!3PHH HHXh!5!5XXhHHHH#33HHH88Xh %!!#!!PHPHPHX %##!##PHHH@HXh %!###!PHHHHP@HPh 5!5!5!#!PHHHx %##5!#HHHh 7#5!#3!5!HH@HxX 3!!!!HPHHHX 33!3PHhH H@X 33!!3PHPhH PHHHP !5!5!5!PxHHH 33!533HHhH H !5333!5HHHh H@xHX 3!!!!H8PHHHPX 33#+3PHHHH8X 3!##33HHHH8HP@PHP #!5!5!5!3PHHHHH ##53#3HHHH8 3#5!#!533PHHHH8H@HXh %#!5!5!5!PHXXPHHHX %###5!##PHHXHHHXh #!#%!##%!5!HhHXXHHHX !!5!3!5!PHXhHHxHX 33!533PHH HHX !33533!5XHHP PHHHHHX!!!!#!5!5!5!3PHHhHHHPHHHX333#####533HHHHHH HHX %##5%!533!##33HHHHHHHHHP@PHX5!XX!XX!X8,!,8,X!,,8Y #'+/37;#5##5#5##5#5##5#5##5#5#5#5#5#5!#5!#5ddd,ddd,ddd,ddddddddddddd,d,dddddddddddddddddXdddddddd ddddddX  &,4<DLRX`hpx~3#73#'73#'73#'?3#'73#'53#?3#'?3#'73#'?3#'73#'53#?3#'?3#'73#'?3#'73#'53#?3#'?3#'73#'?3#'73#'53#?3#'?3#'3#573#573#5dcdbdbbbbbcc ccbbbbbbbbcc ccbbbbbbbbcc ccbbbbbbbbcc ccbbbbbdbdcdcdcccbbbcdbcbcbbbbbbcdbcbcbbbbbbcdbcbcbbbbbbcdbcbcbbbccccdc X!%)-159=!535#535#535#535#53533533535##5#5##5#5##5#5##5#Xdddddddddddddddddd,ddd,ddd,ddddddddddddddddd ddddddddddddddddS753ƍf_7f_s(SX7(0Sf`!fS0-00SSA2"&47"2654&ҴEbbbcMbEDccDEb= 3!"2654=R::R:"R;)(::()F4 "264!2"&546 4Dcbbb4bEDccDEbF3 $52"&546"264$2"&462#"&4#"'&'3276,t覥ʏʏ   0Zb0 6\]63tuut&ʏ   ;6>>J/U0??F3 "62"&546"32654&3"32654&'#"'&'327>,t覥J6]\6 0bY23tuutW/??0S/J>>R@-7'7>353273#'#5"''7.5#534>"2654B*B::6C)B^^%B)C ::9#B*C__pMNnOA)B^^B)B9:/.B)B ^_%B)B8:;N78OO87&33##5#535"&54632&"264Fzz2zz$TT<=SXN77N7A/}}/AP>=UW:?P7N77NZw3,67&'&5432327632#"'#"&54632"264&1h7  + c#R?;TR@*,,27N77h *!  [c'5;YS<:W2;#'77N7N 3&%5##"&54767>7#"'#!726*%0);V%$" 2;;(9+G++VS\"#<)FF'>*6K56=&,:W7A-]F36)?>76=##"&54677.546327632#"&'&'|3267632547&#"3X2 hh>,1M  3,& h2 "8///D/81 8? "8/DX $3!53#5354>32&#"#53͋ )$A6 I//D/8$,2"6DwwXq 3!53#5354>32&#"3#͋;*<=O,#*b//D/9!- !4/V#'48<353#5354>267632&#"333'3547&#"#53OOO:P8 *" Q- (" PB/D/812  8/sDd53C !DDwwVq(7353#5354>326763233'3547&#"&#"3#OOO<).9(3232?>V" !)&"! %KA/%99&%:'#Dys 2#"&54! g_edRwdd:(! ):|;HH;~s5\mh_6776nYtU37]c3#VL?cn"+7#"''7&54>32"'&"324&'.>&P9,(."B%P:)T: & V9KS:ee;IXQ9bg<5ZS0}DA2JBI333#327#"'.=#53%3#2 *E|~PO- DDgmG3/.4-9-?>/s#73#5##"&54632354&#"263#U>k]V0`[NDdcdglG`/JT[a}.( Bl`bbQH75!Jnm "22"&5462#".54>"2>4.,"#,##N?(%P:/G'(T; 9T; ` 3=LB$9bf<*@YN,$BL=35ZR^SZ55ZS^SYF4 '77''!! $$$$d4""$$4>;D$35335&'&5462353#5654&" />$OO)#/ݫg8& IroosH &8gv'cwxb$v.*!!.K2$k2#332676=#533#5##"&'&'##$ %B>RSG$!< 1R0,1&K*{)5  ;*3 !#!73!53#%3#;{/ ddhmG3/+//UC2"&4Ӳ~~~~~~=!3>323#5354&#"3#53#3#( $F"DQPV5-IdTRR`HA8\I//6@O//P) 8Q%3!535#535'#53#7#53#3Gww=LL232#"&547#"&46767>327>54#"(" >+, !   4G*"B 8*' #O%&S   {`- :C)+ "t/#1'=!!1 =7e!c 73!53%3#kڮrJgmGU// (R (  O~  P {  P 5  \ Copyright (c) IBM Corporation 1990,1991.Copyright (c) IBM Corporation 1990,1991.BlessCourierBlessCourierRegularRegularFontForge 2.0 : BlessCourier : 10-5-2020FontForge 2.0 : BlessCourier : 10-5-2020BlessCourierBlessCourierVersion 001.003 Version 001.003 BlessCourierBlessCourier2  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghjikmlnoqprsutvwxzy{}|~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~microAmacronamacronAbreveabreveAogonekaogonek Ccircumflex ccircumflex Cdotaccent cdotaccentDcarondcarondbarEmacronemacron Edotaccent edotaccentEogonekeogonekEcaronecaron Gcircumflex gcircumflex Gdotaccent gdotaccentGcedilla Hcircumflex hcircumflexHbarhbarItildeitildeImacronimacronIogonekiogonekIJij Jcircumflex jcircumflexKcedillakcedilla kgreenlandicLacutelacuteLcedillalcedillaLcaronlcaronLdotldotNacutenacuteNcedillancedillaNcaronncaronEngengOmacronomacron Ohungarumlaut ohungarumlautRacuteracuteRcedillarcedillaRcaronrcaronSacutesacute Scircumflex scircumflexTcedillatcedillaTcarontcaronTbartbarUtildeutildeUmacronumacronUbreveubreveUringuring Uhungarumlaut uhungarumlautUogonekuogonekZacutezacute Zdotaccent zdotaccentgacuteGammaThetaSigmaPhialphadeltaepsilonsigmatauphi underscoredbl exclamdbloverline zerosuperior foursuperior fivesuperior sixsuperior sevensuperior eightsuperior ninesuperior plussuperior minussuperiorparenleftsuperiorparenrightsuperior nsuperiorPtsohm oneeighth threeeighths fiveeighths seveneighths arrowleftarrowup arrowright arrowdown arrowbothSM760000SM770000carriagereturn rightangle intersectionsimilar equivalenceSM790000SM680000SS260000SS270000SF100000SF110000SF010000SF030000SF020000SF040000SF080000SF090000SF060000SF070000SF050000SF430000SF240000SF510000SF520000SF390000SF220000SF210000SF250000SF500000SF490000SF380000SF280000SF270000SF260000SF360000SF370000SF420000SF190000SF200000SF230000SF470000SF480000SF410000SF450000SF460000SF400000SF540000SF530000SF440000SF600000SF570000SF610000SF580000SF590000SF140000SF150000SF160000 filledboxSM600000SM590000SV040000SM630000SM750000SM570001SM750002SS000000SS010000SM690000femalemalespadeclubheartdiamond musicalnotemusicalnotedblffffifflapproxequalalt productdotSM490000 commasuperior zeroslash tquoteright dquoterightSM700000zerodotSP500000underscorebroken spacenumeric LquoterightSM580000 highcommanyuanperiodsuperiorliterlongdash lquoteright "* ,latnliga OLI latnڇobless-0.6.3/data/bless-default.layout000066400000000000000000000015761374060072200175440ustar00rootroot00000000000000 dark red white dark red white dark green white upper dark green white bless-0.6.3/data/bless.desktop000066400000000000000000000003261374060072200162460ustar00rootroot00000000000000[Desktop Entry] Version=1.0 Name=Bless Hex Editor GenericName=Hex Editor Exec=bless %F Comment=Edit binary files Terminal=false Type=Application Categories=GTK;Development; Icon=bless GenericName[en_US]=Hex Editor bless-0.6.3/data/default-preferences.xml000066400000000000000000000020341374060072200202060ustar00rootroot00000000000000 True False Insert True False True True Memory True Hexadecimal True True False False True True False 100 True bless-0.6.3/data/help_script.sh000077500000000000000000000015461374060072200164230ustar00rootroot00000000000000#!/bin/sh base_dir="$1" docbook_help="$base_dir/index.docbook" html_help="$base_dir/index.html" # try to get default browsers from GConf GCONFTOOL=$(which gconftool-2 2> /dev/null) if [ -n "$GCONFTOOL" ]; then help_browser=$("$GCONFTOOL" --get "/desktop/gnome/url-handlers/ghelp/command") help_browser=$(echo "$help_browser" | sed s/\"//g) http_browser=$("$GCONFTOOL" --get "/desktop/gnome/url-handlers/http/command") http_browser=$(echo "$http_browser" | sed s/\"//g) fi # some other browsers yelp_browser=$(which yelp 2> /dev/null) firefox_browser=$(which firefox 2> /dev/null) ([ -n "$help_browser" ] && $(printf "$help_browser" "$docbook_help")) || ([ -n "$yelp_browser" ] && "$yelp_browser" "$docbook_help") || ([ -n "$http_browser" ] && $(printf "$http_browser" "$html_help")) || ([ -n "$firefox_browser" ] && "$firefox_browser" "$html_help") bless-0.6.3/data/meson.build000066400000000000000000000012631374060072200157060ustar00rootroot00000000000000install_subdir( 'ui', install_dir: join_paths(get_option('datadir'), meson.project_name()), ) install_data( files( 'bless-16-bytes-per-row.layout', 'bless-48x48.png', 'bless-about.png', 'bless-all-number-bases.layout', 'bless-binary-ascii.layout', 'bless-courier.ttf', 'bless-default.layout', 'default-preferences.xml', 'help_script.sh', ) ) install_data( 'bless.desktop', install_dir: join_paths(get_option('datadir'), 'applications'), ) install_data( 'bless-48x48.png', rename: 'bless.png', install_dir: join_paths(get_option('datadir'), 'icons', 'hicolor', '48x48', 'apps'), ) bless-0.6.3/data/ui/000077500000000000000000000000001374060072200141575ustar00rootroot00000000000000bless-0.6.3/data/ui/BitwiseOperationsPlugin.ui000066400000000000000000000115631374060072200213550ustar00rootroot00000000000000 AND OR XOR NOT Hexadecimal Decimal Octal Binary Text True 6 6 True True 0 True False False True model3 0 False False 1 True 2 True as False False 3 True model4 0 4 True gtk-execute True False False 5 True True GTK_RELIEF_NONE False True gtk-close 1 False False 6 bless-0.6.3/data/ui/ConversionTablePlugin.ui000066400000000000000000000501411374060072200207730ustar00rootroot00000000000000 True 6 5 7 True True GTK_RELIEF_NONE False True gtk-close 1 6 7 GTK_FILL True 0 0 True False 8 5 6 4 5 True 0 0 True False 16 5 6 2 3 True 0 0 True False 16 5 6 1 2 True 0 0 True False 16 5 6 True False 5 6 3 4 True 1 ASCII Text: 4 5 4 5 GTK_FILL 6 True 0 True Show unsigned as hexadecimal True True 2 4 4 5 GTK_FILL True 0 True Show little endian decoding True True True 2 4 5 True 0 0 True False 22 3 4 3 4 True 0 0 True False 16 3 4 2 3 True 0 0 True False 16 3 4 1 2 True 0 0 True False 16 3 4 True 0 0 True False 8 1 2 2 3 True 0 0 True False 8 1 2 1 2 True 0 0 True False 8 1 2 True 0 0 True False 8 1 2 3 4 True 1 Binary: 4 5 3 4 GTK_FILL 6 True 1 Octal: 4 5 2 3 GTK_FILL 6 True 1 Decimal: 4 5 1 2 GTK_FILL 6 True 1 Hexadecimal: 4 5 GTK_FILL 6 True 1 Float 64 bit: 2 3 3 4 GTK_FILL 6 6 True 1 Float 32 bit: 2 3 2 3 GTK_FILL 6 6 True 1 Unsigned 32 bit: 2 3 1 2 GTK_FILL 6 6 True 1 Signed 32 bit: 2 3 GTK_FILL 6 6 True 1 Unsigned 16 bit: 3 4 GTK_FILL 6 6 True 1 Signed 16 bit: 2 3 GTK_FILL 6 6 True 1 Unsigned 8 bit: 1 2 GTK_FILL 6 6 True 1 Signed 8 bit: GTK_FILL 6 6 bless-0.6.3/data/ui/ExportDialog.ui000066400000000000000000000276731374060072200171360ustar00rootroot00000000000000 True 6 True 3 2 6 6 True 6 True True True Save Pattern True gtk-save False False 1 True True gtk-delete False False 2 1 2 2 3 True 0 0 True 1 2 1 2 True 0 Export _pattern: True 2 3 GTK_FILL True 6 True True True gtk-open False 1 1 2 True 0 Export _type: True 1 2 GTK_FILL True 0 Export to _file: True GTK_FILL False False True 0 <b>Range</b> True 1 True True True True _Whole file True True True False False True Current _selection True True True WholeFileRadio 1 True 6 True F_rom True True WholeFileRadio True False False False 1 True to 2 True False False False 3 2 1 2 True 6 True True gtk-cancel True False False 1 3 bless-0.6.3/data/ui/FindReplacePlugin.ui000066400000000000000000000334411374060072200200560ustar00rootroot00000000000000 Hexadecimal Decimal Octal Binary Text True 6 2 7 6 6 True False model1 0 3 4 1 2 GTK_FILL GTK_FILL True False model1 0 3 4 GTK_FILL GTK_FILL True False True GTK_RELIEF_NONE False True 0 0 True 2 True gtk-go-down False False True Find Next True False False 1 4 5 6 True False True GTK_RELIEF_NONE False True 0 0 True 2 True gtk-find-and-replace False False True Replace True False False 1 4 5 1 2 GTK_FILL 6 True as 2 3 1 2 GTK_FILL 6 True as 2 3 GTK_FILL 6 True False True Replace All GTK_RELIEF_NONE True False 5 6 1 2 GTK_FILL True False True GTK_RELIEF_NONE False True 0 0 True 2 True gtk-go-up False False True Find Previous True 10 False False 1 5 6 GTK_FILL True True True 1 2 1 2 True True True 1 2 True 0 Replace with: True 1 2 GTK_FILL True 0 Search for: True GTK_FILL True GTK_RELIEF_NONE True gtk-close 1 6 7 GTK_FILL GTK_FILL bless-0.6.3/data/ui/GotoOffsetPlugin.ui000066400000000000000000000075511374060072200177640ustar00rootroot00000000000000 True 6 6 True 0 Offset: True False False True True 1 True True GTK_RELIEF_NONE False True 0 0 True 2 True gtk-jump-to False False True Go to Offset True False False 1 False False 6 2 True True GTK_RELIEF_NONE False True gtk-close 1 False 3 bless-0.6.3/data/ui/LayoutSelectionDialog.ui000066400000000000000000000041521374060072200207630ustar00rootroot00000000000000 True True True 0 True True GTK_POLICY_NEVER GTK_POLICY_AUTOMATIC True True False True True Available Layouts False False True 0 True Preview True True bless-0.6.3/data/ui/MainWindow.ui000066400000000000000000000022161374060072200165730ustar00rootroot00000000000000 True Bless - Gtk# Hex Editor 400 400 True True 2 bless-0.6.3/data/ui/PreferencesDialog.ui000066400000000000000000000664461374060072200201170ustar00rootroot00000000000000 1000 0 10 1 99 Hexadecimal Decimal Octal Binary Text Insert Overwrite True True True True 6 True True False True 12 12 True 6 True 0 <b>Default Layout</b> True False False True True False False True 6 True 6 True Layout _File: True LayoutFileEntry False False True True 1 True True True 0 0 True 2 True gtk-open False False True _Select Layout True False False 1 False False 2 False False True True Use layout of currently active _tab if any True True False False 1 False False 1 False False 1 False False True 6 True 0 <b>Misc</b> True False False True True False False True 2 2 6 6 True True True True gtk-open False 1 1 2 1 2 True 0 Temporary Directory: 1 2 True 0 Default _edit mode: True GTK_FILL True model5 0 1 2 GTK_FILL GTK_FILL False False 1 False False 1 False False 1 True 12 6 True True _Load previous session on startup True True False False 2 True True False False True 6 True False True _Ask before loading session True True False False True False True Remember cursor _position True True False False 1 True False True Remember _window geometry True True False False 2 False False 1 False 1 True 12 12 True 6 True 0 <b>Undo Limit</b> True False False True True False False True 6 True 6 True True _Limit to True True False False True True adjustment1 1 True GTK_UPDATE_IF_VALID False False 1 True actions False False 2 False False True True _Unlimited Undo True True UndoLimitedRadioButton False False 1 False False 1 False False 1 False True 6 True 0 <b>Keep Undo History After Save</b> True False False True True False False True 6 True True Always True True True What fits in main memory True True KeepUndoAlwaysRadioButton 1 True True Never True KeepUndoAlwaysRadioButton 2 False False 1 False False 1 False 1 bless-0.6.3/data/ui/ProgressDialog.ui000066400000000000000000000041701374060072200174440ustar00rootroot00000000000000 True 7 12 True 0 label4 False False True True False False 1 True 0.10000000149011612 False False 2 True GTK_BUTTONBOX_END True True Cancel True False False 3 bless-0.6.3/data/ui/ProgressDisplayPlugin.ui000066400000000000000000000016551374060072200210360ustar00rootroot00000000000000 True 6 6 True True True gtk-cancel True False False 1 bless-0.6.3/data/ui/SelectRangePlugin.ui000066400000000000000000000111751374060072200200760ustar00rootroot00000000000000 True 6 6 True Select range from: False False True True 1 True to/±length False False 2 True True Use +/- to specify selection length instead of the absolute ending offset 3 True True GTK_RELIEF_NONE False True 0 0 True 2 True gtk-apply False False True Select True False False 1 False False 4 True True GTK_RELIEF_NONE False True gtk-close 1 False False 5 bless-0.6.3/doc/000077500000000000000000000000001374060072200133765ustar00rootroot00000000000000bless-0.6.3/doc/developer/000077500000000000000000000000001374060072200153635ustar00rootroot00000000000000bless-0.6.3/doc/developer/bless-docs.source000066400000000000000000000001651374060072200206450ustar00rootroot00000000000000 bless-0.6.3/doc/developer/en/000077500000000000000000000000001374060072200157655ustar00rootroot00000000000000bless-0.6.3/doc/developer/en/Bless.Buffers.xml000066400000000000000000000002111374060072200211440ustar00rootroot00000000000000 To be added. To be added. bless-0.6.3/doc/developer/en/Bless.Buffers/000077500000000000000000000000001374060072200204305ustar00rootroot00000000000000bless-0.6.3/doc/developer/en/Bless.Buffers/ByteBuffer+ChangedHandler.xml000066400000000000000000000013541374060072200260350ustar00rootroot00000000000000 Bless.Buffers 0.0.0.0 System.Delegate System.Void To be added. Handler for events. To be added. bless-0.6.3/doc/developer/en/Bless.Buffers/ByteBuffer.xml000066400000000000000000000665131374060072200232220ustar00rootroot00000000000000 Bless.Buffers 0.0.0.0 System.Object Bless.Buffers.IBuffer System.Reflection.DefaultMember("Item") Constructor Create a new empty .To be added. Constructor The filename of this .Create a new with a name. This doesn't load a file into the . It just gives it the specified name. To create a from a file use . Property System.Boolean To be added.To be added.To be added. Method System.Void The to append.Appends a byte to this .To be added. Method System.Void The array of bytes to append.Appends an array of bytes to this .To be added. Method System.Void The array of bytes to get the data from.The starting index in the array of the sub-array to append.The length of the sub-array to append.Appends to this a sub-array of bytes contained in a byte array.To be added. Method System.Void Treat subsequent actions in this as a single one.See also . Method System.IAsyncResult A callback used to report progress.A callback called when the save operation has finished (successfully or not).Saves this under the same filename.An object used to represent the state of the asynchronous save operation. It can be used to wait for the operation to complete. During the save operation no read, modify or file operations are allowed on this . When saving (under the same filename), the is first saved to a temporary file in the directory and then moved over to its final location. The returned by the method and also passed in the callback is a object. bool doSaveProgressCallback(object o, ProgressAction action) { ... } void doSaveFinishedCallback(IAsyncResult ar) { SaveOperation so = (SaveOperation)ar.AsyncState; if (so.Result == SaveOperation.OperationResult.Finished) { // save went ok System.Console.WriteLine("Save went OK!"); } else if (so.Result == SaveOperation.OperationResult.Cancelled) { // save cancelled System.Console.WriteLine("Save was cancelled"); } else if (so.Result == SaveOperation.OperationResult.CaughtException) { System.Console.WriteLine("Save caught exception: {0}", so.ThreadException.Message); } } void doSave() { ByteBuffer bb = new ByteBuffer("test.txt"); bb[10] = 0xff; bb.BeginSave(doSaveProgressCallback, doSaveFinishedCallback); } Method System.IAsyncResult The filename of the file to save this to.A callback used to report progress.A callback called when the save as operation has finished (successfully or not).Saves this under the specified filename.An object used to represent the state of the asynchronous save operation. It can be used to wait for the operation to complete. During the save as operation no read, modify or file operations are allowed on this . The returned by the method and also passed in the callback is a object. bool doSaveAsProgressCallback(object o, ProgressAction action) { ... } void doSaveAsFinishedCallback(IAsyncResult ar) { SaveAsOperation so = (SaveAsOperation)ar.AsyncState; if (so.Result == SaveAsOperation.OperationResult.Finished) { // save went ok System.Console.WriteLine("Save went OK!"); } else if (so.Result == SaveAsOperation.OperationResult.Cancelled) { // save cancelled System.Console.WriteLine("Save was cancelled"); } else if (so.Result == SaveAsOperation.OperationResult.CaughtException) { System.Console.WriteLine("Save caught exception: {0}", so.ThreadException.Message); } } void doSave() { ByteBuffer bb = new ByteBuffer("test.txt"); bb[10] = 0xff; bb.BeginSaveAs("new_test.txt", doSaveAsProgressCallback, doSaveAsFinishedCallback); } Property System.Boolean Whether this has any actions that were undone and can be redone.To be added.To be added. Property System.Boolean Whether this has any actions that can be undone.To be added.To be added. Event Bless.Buffers.ByteBuffer+ChangedHandler Event launched when this is modified.To be added. Method System.Void Closes the file associated with this . To be added. Method System.Void The position of the first byte to delete.The position of the last byte to delete.Deletes the bytes in the specified range.To be added. Method System.Void Emits the changed event.See . Property System.Boolean Whether this will emit events.To be added.See for a list of events that emits. Method System.Void Emits the File Changed event.See . Method System.Void Emits the Permission Changed event.See . Method System.Void Stop treating subsequent actions in this as a single one.See also . Event Bless.Buffers.ByteBuffer+ChangedHandler Event launched when the file associated with this is modified outside of this .To be added. Property System.String The path of the file associated to this .To be added.To be added. Property System.Boolean Whether file operations are allowed on this .To be added.If set to all file operations (save, close etc) are silently ignored. Method Bless.Buffers.ByteBuffer The path of the file to load into the created .Create a new and initialize it with the contents of a file.The created .To be added. Property System.Boolean Whether this has changed since the previous save.To be added.To be added. Property System.Boolean Whether this has a file associated with it.To be added.To be added. Method System.Void To be added.To be added.To be added.To be added. Method System.Void To be added.To be added.To be added.To be added.To be added.To be added. Property System.Byte The index (position) in the of the byte to access.Provides access to the bytes in this .The byte to write to or read from the specified index. If the property is set to all attempts to read return the byte 0.If the index is outside the range of the this method throws a . Field System.Object Object used to ensure synchronized access to this .To be added. Property System.Int32 The maximun number of actions that can be undone.The number of actions or -1 for unlimited undo actions.When the number of undo actions is set to be less than the current number, older undo actions are lost. Property System.Boolean Whether this can be modified. To be added.If set to , all buffer actions that can modify the buffer are silently ignored. Event Bless.Buffers.ByteBuffer+ChangedHandler Event launched when the permissions of this are modified.To be added. Property Bless.Util.Range The range of this .To be added.To be added. Method System.Byte[] To be added.To be added.To be added.To be added. Method Bless.Buffers.SegmentCollection To be added.To be added.To be added.To be added. Method System.Int32 To be added.To be added.To be added.To be added.To be added.To be added. Property System.Boolean Whether this can be safely read.To be added.If it is set to , all attempts to read from this return one or more bytes of value 0. Method System.Void Redo the last undone action.This method does nothing if there is no action to redo. Method System.Void To be added.To be added.To be added.To be added.To be added. Method System.Void To be added.To be added.To be added.To be added.To be added.To be added.To be added. Method System.Void Revert this to its saved state.The method only works if this has a file assocciated with it. Property System.Int64 The size of this in bytes.To be added.To be added. Property System.String The directory where temporary files related to this are stored.To be added.When saving under the same filename, the is first saved to a temporary file in this directory and then moved over to its final location. Method System.Void Undo the last done action.This method does nothing if there is no action to undo. Property System.Boolean Whether to use the GLib Idle handler for progress reporting.To be added. The default value is . This should be set to if progress reporting involves Gtk+ widgets. A buffer for holding bytes in a versatile manner. It supports undo-redo and can easily handle large files. Editing is also very cheap. To be added. bless-0.6.3/doc/developer/en/Bless.Buffers/FileBuffer.xml000066400000000000000000000153661374060072200231760ustar00rootroot00000000000000 Bless.Buffers 0.0.0.0 System.Object Bless.Buffers.IBuffer System.Reflection.DefaultMember("Item") Constructor The path of the file.Creates a from a file.To be added. Constructor The path of the file.The size of the moving data window.Creates a from a file and using the specified window size.To be added. Method System.Void To be added.This is a read-only buffer.To be added. Method System.Void To be added.To be added.To be added.This is a read-only buffer.To be added. Method System.Void To be added.To be added. Property System.String The path of the file loaded in this .To be added.To be added. Method System.Void To be added.To be added.To be added.To be added.This is a read-only buffer.To be added. Property System.Byte To be added.Provides access to the bytes in this .To be added.To be added. Method System.Void To be added.Loads a file in this .If the already has a file loaded, the old file is closed first. Method System.Int32 To be added.To be added.To be added.To be added.To be added.To be added. Property System.Int64 The size of this .To be added.To be added. A buffer that allows efficient access to a file by using a moving data window. This is a read-only buffer, so any attempt to modify it is silently ignored. The buffer works by keeping only a portion of the file's data in memory, in what is called the data window. An attempt to read data that is currently outside the data window causes the data window to be reloaded. Ofcourse, this procedure is transparent to the caller. bless-0.6.3/doc/developer/en/Bless.Buffers/IBuffer.xml000066400000000000000000000073401374060072200225000ustar00rootroot00000000000000 Bless.Buffers 0.0.0.0 System.Reflection.DefaultMember("Item") Method System.Void To be added.To be added.To be added. Method System.Void To be added.To be added.To be added.To be added.To be added. Method System.Void To be added.To be added.To be added.To be added.To be added.To be added. Property System.Byte To be added.To be added.To be added.To be added. Method System.Int32 To be added.To be added.To be added.To be added.To be added.To be added. Property System.Int64 To be added.To be added.To be added. An interface describing a buffer. To be added. bless-0.6.3/doc/developer/en/Bless.Buffers/SaveAsOperation+SaveAsStage.xml000066400000000000000000000021101374060072200263510ustar00rootroot00000000000000 Bless.Buffers 0.0.0.0 System.Enum Field Bless.Buffers.SaveAsOperation+SaveAsStage To be added. Field Bless.Buffers.SaveAsOperation+SaveAsStage To be added. To be added. To be added. bless-0.6.3/doc/developer/en/Bless.Buffers/SaveAsOperation.xml000066400000000000000000000074121374060072200242210ustar00rootroot00000000000000 Bless.Buffers 0.0.0.0 Bless.Util.ThreadedAsyncOperation Constructor To be added.To be added.To be added.To be added.To be added.To be added.To be added. Property Bless.Buffers.ByteBuffer To be added.To be added.To be added. Field Bless.Buffers.ByteBuffer To be added.To be added. Field System.Int64 To be added.To be added. Property System.Int64 To be added.To be added.To be added. Property System.String To be added.To be added.To be added. Field System.String To be added.To be added. Property Bless.Buffers.SaveAsOperation+SaveAsStage To be added.To be added.To be added. To be added. To be added. bless-0.6.3/doc/developer/en/Bless.Buffers/SaveOperation+SaveStage.xml000066400000000000000000000025341374060072200256130ustar00rootroot00000000000000 Bless.Buffers 0.0.0.0 System.Enum Field Bless.Buffers.SaveOperation+SaveStage To be added. Field Bless.Buffers.SaveOperation+SaveStage To be added. Field Bless.Buffers.SaveOperation+SaveStage To be added. To be added. To be added. bless-0.6.3/doc/developer/en/Bless.Buffers/SaveOperation.xml000066400000000000000000000041401374060072200237300ustar00rootroot00000000000000 Bless.Buffers 0.0.0.0 Bless.Buffers.SaveAsOperation Constructor To be added.To be added.To be added.To be added.To be added.To be added.To be added. Property Bless.Buffers.SaveOperation+SaveStage To be added.To be added.To be added. Property System.String To be added.To be added.To be added. To be added. To be added. bless-0.6.3/doc/developer/en/Bless.Buffers/Segment.xml000066400000000000000000000074421374060072200225630ustar00rootroot00000000000000 Bless.Buffers 0.0.0.0 System.Object Constructor To be added.To be added.To be added.To be added.To be added. Property Bless.Buffers.IBuffer To be added.To be added.To be added. Method System.Boolean To be added.To be added.To be added.To be added.To be added. Property System.Int64 To be added.To be added.To be added. Method System.Void To be added.To be added. Property System.Int64 To be added.To be added.To be added. Method Bless.Buffers.Segment To be added.To be added.To be added.To be added. Property System.Int64 To be added.To be added.To be added. To be added. To be added. bless-0.6.3/doc/developer/en/Bless.Buffers/SegmentCollection.xml000066400000000000000000000102531374060072200245710ustar00rootroot00000000000000 Bless.Buffers 0.0.0.0 System.Object Constructor To be added.To be added. Method System.Void To be added.To be added.To be added. Method Bless.Buffers.SegmentCollection To be added.To be added.To be added.To be added.To be added. Method Bless.Buffers.Segment To be added.To be added.To be added.To be added.To be added.To be added. Method Bless.Buffers.SegmentCollection To be added.To be added.To be added.To be added.To be added. Method System.Void To be added.To be added.To be added.To be added. Property Bless.Util.List<Bless.Buffers.Segment> To be added.To be added.To be added. To be added. To be added. bless-0.6.3/doc/developer/en/Bless.Buffers/SimpleBuffer.xml000066400000000000000000000103651374060072200235420ustar00rootroot00000000000000 Bless.Buffers 0.0.0.0 System.Object Bless.Buffers.IBuffer System.Reflection.DefaultMember("Item") Constructor To be added.To be added. Method System.Void To be added.To be added.To be added. Method System.Void To be added.To be added.To be added.To be added.To be added. Method System.Void To be added.To be added.To be added.To be added.This is an append-only buffer.To be added. Property System.Byte To be added.To be added.To be added.To be added. Method System.Int32 To be added.To be added.To be added.To be added.To be added.To be added. Property System.Int64 To be added.To be added.To be added. A simple and lightweight append-only buffer implementing the interface. To be added. bless-0.6.3/doc/developer/en/Bless.Util.xml000066400000000000000000000002061374060072200204710ustar00rootroot00000000000000 To be added. To be added. bless-0.6.3/doc/developer/en/Bless.Util/000077500000000000000000000000001374060072200177515ustar00rootroot00000000000000bless-0.6.3/doc/developer/en/Bless.Util/BaseConverter.xml000066400000000000000000000107351374060072200232430ustar00rootroot00000000000000 Bless.Util 0.0.0.0 System.Object Method System.Int64 The string to convert.The number base of the number represents.Converts a string to a number assuming it is represented in the specified number base.To be added.To be added. Method System.Int64 The string to read the sub-string from.The starting index of the sub-string in .The ending index of the sub-string in .The number base of the number that the sub-string represents.Converts a sub-string of string to a number assuming it is represented in the specified number base.To be added.To be added. Method System.String To be added.To be added.To be added.To be added.To be added. Method System.String To be added.To be added.To be added.To be added.To be added.To be added.To be added.To be added. Field System.Int32[] To be added.To be added. Method System.Int64 To be added.To be added.To be added.To be added. Class to convert numbers to strings and vice-versa using any number base (up to 16). To be added. bless-0.6.3/doc/developer/en/Bless.Util/ByteArray.xml000066400000000000000000000031151374060072200223750ustar00rootroot00000000000000 Bless.Util 0.0.0.0 System.Object Method System.Byte[] To be added.To be added.To be added.To be added.To be added. Method System.String To be added.To be added.To be added.To be added.To be added. To be added. To be added. bless-0.6.3/doc/developer/en/Bless.Util/ConfigureDefines.xml000066400000000000000000000044601374060072200237160ustar00rootroot00000000000000 Bless.Util 0.0.0.0 System.Object Constructor To be added.To be added. Field System.String To be added.To be added. Field System.String To be added.To be added. Field System.String To be added.To be added. Field System.String To be added.To be added. Field System.String To be added.To be added. To be added. To be added. bless-0.6.3/doc/developer/en/Bless.Util/Deque`1.xml000066400000000000000000000104461374060072200217640ustar00rootroot00000000000000 Bless.Util 0.0.0.0 T System.Object System.Collections.Generic.IEnumerable<T> Constructor To be added.To be added. Method System.Void To be added.To be added.To be added. Method System.Void To be added.To be added.To be added. Method System.Void To be added.To be added. Property System.Int32 To be added.To be added.To be added. Method System.Collections.Generic.IEnumerator<T> To be added.To be added.To be added. Method T To be added.To be added.To be added. Method T To be added.To be added.To be added. Method T To be added.To be added.To be added. Method T To be added.To be added.To be added. To be added. To be added. To be added. bless-0.6.3/doc/developer/en/Bless.Util/FileResourcePath.xml000066400000000000000000000043331374060072200237020ustar00rootroot00000000000000 Bless.Util 0.0.0.0 System.Object Method System.String System.ParamArray To be added.To be added.To be added.To be added. Method System.String System.ParamArray To be added.To be added.To be added.To be added. Method System.String System.ParamArray To be added.To be added.To be added.To be added. To be added. To be added. bless-0.6.3/doc/developer/en/Bless.Util/List`1+Node.xml000066400000000000000000000041131374060072200225070ustar00rootroot00000000000000 Bless.Util 0.0.0.0 T System.Object Constructor To be added.To be added.To be added.To be added.To be added. Field T To be added.To be added. Field Bless.Util.List<T>+Node To be added.To be added. Field Bless.Util.List<T>+Node To be added.To be added. To be added. To be added. bless-0.6.3/doc/developer/en/Bless.Util/List`1.xml000066400000000000000000000131201374060072200216240ustar00rootroot00000000000000 Bless.Util 0.0.0.0 T System.Object System.Collections.Generic.IEnumerable<T> System.Reflection.DefaultMember("Item") Constructor To be added.To be added. Method Bless.Util.List<T>+Node To be added.To be added.To be added.To be added. Property System.Int32 To be added.To be added.To be added. Method System.Void To be added.To be added. Property Bless.Util.List<T>+Node To be added.To be added.To be added. Method System.Collections.Generic.IEnumerator<T> To be added.To be added.To be added. Method Bless.Util.List<T>+Node To be added.To be added.To be added.To be added.To be added. Method Bless.Util.List<T>+Node To be added.To be added.To be added.To be added.To be added. Property T To be added.To be added.To be added.To be added. Property Bless.Util.List<T>+Node To be added.To be added.To be added. Method System.Void To be added.To be added.To be added. To be added. To be added. To be added. bless-0.6.3/doc/developer/en/Bless.Util/ProgressAction.xml000066400000000000000000000040531374060072200234370ustar00rootroot00000000000000 Bless.Util 0.0.0.0 System.Enum Field Bless.Util.ProgressAction To be added. Field Bless.Util.ProgressAction To be added. Field Bless.Util.ProgressAction To be added. Field Bless.Util.ProgressAction To be added. Field Bless.Util.ProgressAction To be added. Field Bless.Util.ProgressAction To be added. To be added. To be added. bless-0.6.3/doc/developer/en/Bless.Util/ProgressCallback.xml000066400000000000000000000014651374060072200237220ustar00rootroot00000000000000 Bless.Util 0.0.0.0 System.Delegate System.Boolean To be added. To be added. To be added. To be added. To be added. bless-0.6.3/doc/developer/en/Bless.Util/Range.xml000066400000000000000000000116331374060072200215330ustar00rootroot00000000000000 Bless.Util 0.0.0.0 System.Object Constructor To be added.To be added. Constructor To be added.To be added.To be added. Constructor To be added.To be added.To be added.To be added. Method System.Void To be added.To be added. Method System.Boolean To be added.To be added.To be added.To be added. Method System.Void To be added.To be added.To be added.To be added. Property System.Int64 To be added.To be added.To be added. Method System.Void To be added.To be added.To be added. Method System.Boolean To be added.To be added.To be added. Property System.Int64 To be added.To be added.To be added. Method System.Void To be added.To be added. Property System.Int64 To be added.To be added.To be added. To be added. To be added. bless-0.6.3/doc/developer/en/Bless.Util/RangeCollection.xml000066400000000000000000000040301374060072200235400ustar00rootroot00000000000000 Bless.Util 0.0.0.0 System.Collections.ArrayList Constructor To be added.To be added. Method System.Void To be added.To be added. Property Bless.Util.Range To be added.To be added.To be added. Method System.Void To be added.To be added.To be added.To be added. To be added. To be added. bless-0.6.3/doc/developer/en/Bless.Util/TempFile.xml000066400000000000000000000016461374060072200222070ustar00rootroot00000000000000 Bless.Util 0.0.0.0 System.Object Method System.String To be added.To be added.To be added.To be added. To be added. To be added. bless-0.6.3/doc/developer/en/Bless.Util/ThreadedAsyncOperation+OperationResult.xml000066400000000000000000000026431374060072200302320ustar00rootroot00000000000000 Bless.Util 0.0.0.0 System.Enum Field Bless.Util.ThreadedAsyncOperation+OperationResult To be added. Field Bless.Util.ThreadedAsyncOperation+OperationResult To be added. Field Bless.Util.ThreadedAsyncOperation+OperationResult To be added. To be added. To be added. bless-0.6.3/doc/developer/en/Bless.Util/ThreadedAsyncOperation.xml000066400000000000000000000126421374060072200250770ustar00rootroot00000000000000 Bless.Util 0.0.0.0 System.Object Constructor To be added.To be added.To be added.To be added.To be added. Field System.Boolean To be added.To be added. Method System.Void To be added.To be added. Method System.Void To be added.To be added. Method System.Boolean To be added.To be added.To be added. Method System.Void To be added.To be added. Method System.Void To be added.To be added. Field System.AsyncCallback To be added.To be added. Field Bless.Util.ProgressCallback To be added.To be added. Property Bless.Util.ThreadedAsyncOperation+OperationResult To be added.To be added.To be added. Method System.Boolean To be added.To be added.To be added. Property System.Exception To be added.To be added.To be added. Method System.Boolean To be added.To be added.To be added. To be added. To be added. bless-0.6.3/doc/developer/en/Bless.Util/ThreadedAsyncResult.xml000066400000000000000000000052411374060072200244120ustar00rootroot00000000000000 Bless.Util 0.0.0.0 System.Object System.IAsyncResult Constructor To be added.To be added.To be added.To be added.To be added. Property System.Object To be added.To be added.To be added. Property System.Threading.WaitHandle To be added.To be added.To be added. Property System.Boolean To be added.To be added.To be added. Property System.Boolean To be added.To be added.To be added. To be added. To be added. bless-0.6.3/doc/developer/en/index.xml000066400000000000000000000035371374060072200176260ustar00rootroot00000000000000 System.Runtime.CompilerServices.RuntimeCompatibility(WrapNonExceptionThrows=true) System.Runtime.CompilerServices.RuntimeCompatibility(WrapNonExceptionThrows=true) To be added. To be added. Bless bless-0.6.3/doc/user/000077500000000000000000000000001374060072200143545ustar00rootroot00000000000000bless-0.6.3/doc/user/C/000077500000000000000000000000001374060072200145365ustar00rootroot00000000000000bless-0.6.3/doc/user/C/figures/000077500000000000000000000000001374060072200162025ustar00rootroot00000000000000bless-0.6.3/doc/user/C/figures/bless_area_focus.png000066400000000000000000000146561374060072200222230ustar00rootroot00000000000000PNG  IHDR:W_lbKGD pHYs!3tIME ʋ.;IDATxyTgƟnچ H! w".HtbFT$Fs shqMWFG8&c1u fQ8q\(^G7MoU_/9Ozj)>%,.DxujXׯhN]EPhCvU}o P;~D2j0gg>._"ϛСBǎÎ2O4/2vumS#i<8gd`Bo:Ap b40Z Ķ> I@--O؞ "cgf ~th3q~"ysq\oLdT_xpl.0@ZJ Bhu@,Z\X(P@Vr`4Hu$2(b!>vtuзt|u:0QYɀ@ޗ@H>tl#8?5cmr {-Η7"aLv\(e_p }&P['_gt!rUiF:SÁj`|`@QV#z:bGRgw5׀Ӏ+{8;?(ُUP:|8-ɓpeO߱lubr&,]\h ٴE MAs&"Z7E(.fFZ6z =׈?L#ٳG첽4_>h_k皟<j!ct _O@xO.dnYGgD`kY->xpsDhcyME8ҥK|rQM\ SK~P&̙3>aS Am3~u@QeE8f䐜8 h e}#>"\?1/;wmèaYQ`HPq PNwD(?3-|[ "{Ii~wˍ@?G#=` ::5?oοfb._JA7Yw_METs UÚ::DŚ̈A3T#cicz[!Ođ?gZ5BCr(dtċ)%a `@Xs}?ۮ69@yWRŚLפ%/}eK|ί @@/* I0>v9o__`xl 'rq1`Lum%Xaָd'&ah@ ; E5Zg&=yLNW4!;k,{Ao(||F ۃ%?M5D} >p?w9X$CFcJ DJDhލcSD (5%Dд7Z;' I7/wɲ|ie%eȨ'Z5h 5`$HcVjF""^WPҢEǚ߀01jd(E8Bs<"tvfok>fvɽ<":JD.Τ 6Zgeo_}vfS ׺5aS2OH.gU4~+t[LϠCrE_DTnujKU ~zmO.!EP7Q~=9H$3';}QyDFgR\!Bk2tP+]Q[h3a4mbem2Խ%"Bԧ:U}؛~1@?ӧ3PvNDo^6h,;B}))0Nde=4~PBj, m) Х0hPk *?!w XTSxCLE?b+16gkz ӣ\~1)CDw$VYR=#0Y"HPMn.ENnCk4eM?MpGDtQ3::woЂQ)Uᚎh(TX뎎5?w2?tjJ P 蚢,,VQ1bL8=0mFC--'>0|[ozҥK== 05? ?G!Uy:󟗼lGrBtGRq-:~+c+_n,Pq(2Hgzg~LiOt#jő_Sdrs}o4lٗNH_3z߯ik>K@6Hv#<:.Y=Xvh@CΒUGǒ;}5݁e}BsG*JQbFKQǖmv$A;a'[G8 tM NDX5Vswz QB#7Gs1зMwuzō7:....ntd2΀7:....nt\\\\̌GYKGY?k,d@B˟yQB zIRQ-߬EYK-l^z({]YGݿ+MOcuQB{)5/(ueݲ=BQNe⍎u:54gg[u#c͏ѱG!R?|S(5-z:b .oZ<Э:Q JGY;EY;?P(ş<O5c;|(wi^p8M2]:}Ξ39sFu[~,柯.@yu}qmNw,ĚJs؏v,21[Wî>Ssݑi<(ӧaLe-wys/?FYoб?n=a&-y9'kpi 6 㓗:_w+^4ӁMKgToG!JYT޻0̣Ybt\.Q(u.Q\\\\#髷O|5~wt\\\?w񎎋7:...(k(kO3x+Ĥ?CFNAAeXkb($bQB*~.V:~hw({]F9)-fYzd!v&zRQm5>8~~ Q F'6zߠ"s^c<(U@~ D4ɠTQ`t54iJ3Q)5#Y]~}8S}e>̌N)6D29 (N| jQPѨDUZ)Ϗkve5wڄҰqB~6: Hjw`$ e *QmVn2DycO<?Y@ M']GY{DY{SeXр=s^(Z\e0GYۆHV *JQ2x,_lm^X:O}5:R^R'eͣ=τ )'c}޹5?_Ey)Jݝ (k':y_X Rԉ짫5M,F'=K~܋gѱ(hʻZXF'4wt-5"k 21(1ż{FZn*SGao$IQQ#L1̃G®>Sʩh['N De/* I(wP;~M_ Eäw$Bx9(CF(X3dFn]:ߴo+*ϽOz`{6+`TXy,ο2?O51rW., 0hY$^`61Щ/O@\_?|+ lhe< :5˲}oݯˁ+LMen'Ev߭2t*3%ǚ߭ϛEQY]ŷD秚} 4( @61vTvzF$+ WqNJU澧H\U>˅PBٷ4n7Rή~;_>ѫ;tRg7ЊLQ2"i 'gv'r-4ŅFnCl[QA.BHThj/8 l(֙GV-Δ^}p !ONV}I UmGm5 hj>`X'phg0qZE5Lc϶> =8Lf D4'0xٳge{E\{O^[@T74W{3kWBexOTE*ŎnJTHֲZ|@Q௥ME8˗۬`9uP+H?1Jki@7`+F[~ [.e튟" sϻQ,d2KcjY6&ʟ5[p@-:o*1~ߑkFH{bmGːp0qy+@8 *NοV&/wz:tu@@v!p4,ʫ~P~ L_|g8Eǒ><е;RݞX7:"i,5.7s 7;6÷tw*p|U •j5`xm𦢥krGo+ķ'o\?:ZDccSLN(?G{(|AP~Mj-߾x:Uq&\\\丸v?*x)&IENDB`bless-0.6.3/doc/user/C/figures/bless_bitwise_ops.png000066400000000000000000000166751374060072200224460ustar00rootroot00000000000000PNG  IHDRi4bKGD pHYs  tIME  s\JIDATxw|MwdId1%hҐR$1kWU#TjTZhIP[Ԩ-5J ! 3!;ʸWxsw>9yG߂}q'9|~ݲ{y5@ ;e&rܜlrs$ $ JZ"7;["-~M()U lp^||΅Pʕ=|/Ѵ@ O!޹+;W-I̵ܾj۩p(#x^y=(#$&\_ܽ76@P"CVRp;6EclbSgee S(S<uӃB Hh8^K݆H*ֵYYYcCzt_ˍׄӶ--[Lz RnCʭW{`vF@$]PUHDn=ذa]w͑K+ٵ\. U~Vw[cllSm'DTR]ٹ9JCm,򼓜xѝO゙?Gʡ[`6per7IIGpO;Jmڴ9$qXڶlZHN1=/>bmSfɻZU!o_@^JՊSV&N gbEᾎOEe2Z>ZzirzҊXXuin]kWrЃ7=iŝ̙5SSSҹy3ӧb޽\~АT*z*y/ . ._v;xOǎe[1uNl{G%Y>.ʔWXS^m3[yXWć6loܸX>*Yl),\TΜٟ>'8~e|A'xvHJ=4)2$H|u<]Z:pbfȈܜ\rssٻo?k#O>kkk7YeȿOT4e*OyigϞۛP"##-b:t(qqqܾs0 1+jA/#s'—yF݃yn]Ƭ+{-L%S[SoN)df$99.]0v|8cLJӧO_+0Fƕ:Uغ[s4/hP^d'=;Ӹy*a?ˈy&i@,Lv!ٙoø{H˕r˲ TlZ][:`.S~$Ҹ2 "v6ݟ%h͐`>{&$r2;? Ԅ5/ҥO3mW}uV ;Crpè#3k&sfdy]RWYbw%^~VKNt TlO9yo/`D+ Y 6A6r9K9 XuO!9)KG2W?8y6oBdX =Eˈ13YA:=}˹؋܌>e&@VkW{շ֫ H|ۛ7_+7+w1Ǹv=%0MOzb/ǸϒAfWZRRgOV҃% yV15aLN ( 7oFNp= d_?`}ܻsUnn2{XrRB/)!o_Bsi䅷GɖFZb Gcm$pzx\V+Nc<xVkƎ]}_>Y '!0 zb6k↴ =ޢie-OI够&dt _-d+;Uăl^47Vu)Ál٘S 517)kyL[PP}Vo]`q I999\&f,^K۳Y9rKqrsy> SŒϿ BA`MLJ1]eI}QSvׅ} ܿw7nܘHn`gg[>HM$fk+ʌk3{3b׻Uۍ E\(E0H͂aa$GndAq²b/kyJ/J.f1u P'o݇N*!: c'BB{k ;eO|:d.+{[2(pf}b{|U7qh70sX¸tЉ*OZirobyz8~ qr̯~,_3/2;l@y1.\ZBv+9QKޝj&qw Vk2 8u2㈏=cnľL٧wZU3f㭌'Y]W&s }9C BTRsz9*5ܼ vXVۤ׳%Ny}U۹rN&|z83Jll,vb}3Aikvo$!=DфߏEc("6}I݉RێWz8n)f ӫh»ZUbU_*Ce0Z1 `xԤq{#U^Z5vAlƎm@f˜\ћs"F+4w8\Ԧq~;T2`Ή2Ř4yJbo!<'mӱX܉;ΔZzzt5jba,';%%jsAn52^q kJ3cC+y=Xۘ]!zt$,kXF+,W+OB\\TI, w憿.ydsbφbVb ǚVĹmci͐Ai֭[|2b/drFFx{ӷoƎKFzɷtWW7PU:IEvʣ9W%lr?*L\.& +򜓶uN"Dk Ǐ>aDžqq&\JHߕun}Ҿo1!uu;}v[bg$G6O}w: 'Gn¹N=uI v.Il q6d'?bRn))?Z=5 [pܩ'B*!= [ǿגx8r#+oz-\[{gZtg'bBb,DliIS>E|['mmDu.]U ,pŕz9Zzz9tx3qWwi{#Ъu WK<&odo owڮ~s^s!A/K7Sk?h!MVH^b(`fzi\IF2x `@[;g]1MIԷsuv v64i҈C厗;YYܿN;canU-ԫ\󀺹 sGҷw\GO5Y?޾6 y_oOGC]uγ<-b CΖC -bʮ[!; ^'wBv!}?VUc1 .ۓDRg×ɋ ';+?'uR>R 9ٳ4ҳQk#Vb/ITn),Sgp {> y< KՃEùs3]cGٵ{;vDɚHH΋/6~>}8;;rEZ0q8::bff^$bM4,-3__0ǂ6>(r#* ĭ͵J5Р$ҫQk"*Oghfr?/jOz, \nowTJ=X8 JKPp16UK~ 8[[6mĵ7ޭ+.r4mܘ&+'m۞رFJ &V%8nU+뜴V-K4J KX\rLu Whf*yv#)xzP߾.*kfLEsi,su{"I4nCm1m8wi/$VXYڊjU-022B$LMLaiL&HD.k Mtmwa zIRVէ?k"VWܛ5?BVVtzYˆ۷YK੒@Z6ʧ ֋Bejth}̌=e $IPx$INyԵ݅& ɐ$ ZEďWH\ϣ)wo&)W": %y7bXB!EdJ8B_AӃYT:I+NrffE)l.4A\aR0WT_JEnn ybgecOٿ{wP6rYĻ/V6ʋ*7W'=(0^{4Arpz5zcXzU.Jgf^Md } x"\KJzPȃa݀}4Aл)CDEE!++ `aaiӦ!88>>>:յWVV"??BJJ N<:6oތŋC,x`aL>W^:;v`Μ9011m"'_Ĕ?N8www0 tFΝ;\z^^^HLLĝ;w0.+ǝ;w///\z8w[aIJJ ϟT)S࣏>#7L3|GGG߿l/uCMM QSSBbV'@LJ9BR^T*#GpZΝ;dmmc544huQ*nݺvUF1*]apY3Zv llleee =fHRaޭ[7ܹH$Z pttʕ+k%!00666;#:9փG۱cwooo\pAضf͂ W_ݶ6UL`(,,Ĕ)Sp5w)ӽX,Fxx8])SǏGJJ ? c ׮]5+`ff|ܸq.\o)S__<ܻw>^@yy9޽c˖->+V3qE=zTƍD8;>qnnnv>| |F% 55Ço20bD[ڠݺuJb&IK[iW_6?͛7C.sC\͛7+-.lmhLڠ囋>dȐ&u÷2 Qguo9.]d$ \~m'H]"m_եOm8 0QWWdJajj_~YkbqFplܸEGGLF.Rlt]n.D6v3Pll,-^ƎK${ݙb|}}iرxb˖~/V='4eR)M2G< {.۷CݻwTi7n0bD]B(D@Р{ h-_~E&$c4C͍[܎-x{{ Sm^_i|}}a2D7n˗ann #-- :HKKC||<`nn˗/cƍׯu01''_}ƍפ,88l{ sssॗ^A0-#K/!&&HNNVu#h̙:@DL$HFI6mjPRRBb;;&#$??_0u :r1g9r||||1vءd|u;vLMM)eʄ SSS:vXxܼy֬YCdff͉;w.ّ^[DD>,ڒ۰ᓞ.(11C1HLL$///ziСJDDt211S5{⡋C:s EDD yyyѣ)((GCrc<2h%$ 3*"""зo_$%%uLu2 III۷/"""p}իlq0BrssSk^x{.rrrP\\-[BCCz@ii)1gΜVzTUU˗/녲+W(--ի+V q.\7|S㶨GII 3 $$Gdd:WU(Ν;:u*0g۷O&F̍~r GGGZ`믔O4a:sxW]oe EDL(//OK.СCO?%"X Tk[n=駟ёobblN8A~~~M2jonn+++XYY +XTkk(ڹCűcǔڀ1~A.ihh@zz:8"Bhh(Ə333pPz`LMk^Cyy99tܻwyyy(--5޽;zooo3!!!pppuMpqq9rssamm6!!!ضmرcjD&r\,;;nnnM177GCCd2LLLP\\ܡퟕ/bҤI0cS2~73gмy󨼼rd2:tM6Ѳe(22RPPP@ǏWfȑ4a={R "  Pee%544ŋ` 'DB4rHڴiSzR)SRR… -T)U۪3mamm-쎉ᇒ]5|tmq "TUUꫯw}|.ŧ~ !<<|߳g1p@當 _PmX ...سgP~H$ذaC:LLL{nDFFw{+yذaظq#d2֮]e˖)M0ly` @~)Ӈ<==>ksU1FΜ9C#G*BQ+>q#選8@ .$"$ 1rHEsY5;}:nGGGdd/7oĉŅRqq1]`=M4ɇR1]K(((Kի'}z?D^(D@j8Yhhhɉ6m$|aFnn.=B~&Mj/ bcc{SN&/TZZIOO2{yyQbb"V_bb"yyy [JAA7:''ΝK4}6-|ac~ SSSoOFV2w5ѽ:%[!o~_JKKחOަs9vL2Yq4OYYM2Ep=v"[V޼yU5өYn]!88y{{| %$$_vv6 :%6ydklqPX5֮]Sm@*ڵk 7@xТpЧxPe4<==飏>uLb_=UO2;-v4j ,GJٜ-Tڵkpssl,r9ݸqՕ֭[GEEE|.AyyQ=[x1w.h]{7hرYfUCCZ> 6+͘1\L $lhܹ۷ժXT5ŋԭ[-KT?OK榤X<ա=JcÇyraРATXX4jT/k,ӄ\ѣ,NNN-XbXZR?3 0W^*L ֭[Gjω?j`W>ĝO]jjjhĈjEC|4v}oHă\.r;w.b8q"piK y B^4 $.oÇԡnGj ]ի͘8vv% m߾\]]O>tENzŰp⨊B>|4w\MxhxhzŃ[_аaÃO555~%+1)É<=oA}i|ϟ/lI3c+LzŃ\.LZ`?Ov]%¡ccԪIIIDD\WtqqqEj*'"4iّ-M>]ij(,,Y@xONԷo_ڽ{a+ݱc KKKidggGݻw_|Q=z@Q}vrrr"///mKJJh̙dmmM{-Y<xm۶M0222:d1Pg6v1\&m6ݻ7 WWW*..bC%D"D""z'h˖-DG}QYYҥK)$$D?$$ϟO@/^lҙܹzfY\\LƍSE"YٳiѢET]]MEEE4b<["^uJEcƌ={6 ?j(CZZ ]z:}4yyyQ>}?̮LL3'O9sPDDTK<P9y$ 0\BDDTUUE&&&z(:͛7Õ\H,S^^NR4c8qO?D*UW|W^ywO>g}VVVz9?2e ]p]ǵk0ebHIIAaĉ1h 9s0LXZZZ}R)ݻ777@EE"""{gϞ`+ IDAT\\\@DJ6'N/oFrw}ا񱲳477GCCd2Xko5ox֭gyH$zAz/RX̣Om:PZbe鴅H$%KD"z'i(Z W҂ 5gϞ%777t钰O?t &<+9r$mڴISRR… ղ<4Wѣy؅C}}=:ux rss]vQuu^FIi^F.?N666b dY[[SϞ=)::Zc-//0'h>qyxxY^ iڴidmmM~~~gW)JJJhܹdggGNNNzjdBB9::R=hj" $+++ݻ7Ic2~7Zt)9;;SDD8+]f K8tQHWMC!55UXhL111F#G+Wct\9n*H QEII ]z߿O/3A ۛ<<uUp۷/P||Um$룘)et :>Saz$00PŨWUfd#"rqqvE[n%///UVvp-rijj^F(V;U eYʹ9Rܧ-mٳ3f}YYBBB`oogggYRT(/--ŬY`cc???|WJV^YY8::/V n߾nݺ)mccT{n.\@LL \]]克/*mct޸pZhOE*r レ,pYܼy/͛7qY|5BBB$$$ʕ+pwwW҈Β^e2s=GvvvSOQiiFVTTFiwx :1+ Wͨ(Y`kVYhUWWSQQ1l٢TFhԨQJCBBhTQQA tEКUN$믿NRlB={(omh̘1j"5.cӮk/;u^.Smm-8pwNzWj=իպnݺG}wngF[c.4$jcrEݖruxh_~!H$$a_ɩm{4ut>,8sgs\r{'777ڻwER׮]#Xqqq7?n Om fDyTR5-imkP.H>}:^ ;0gXt)d2>’%K'Nie_߿yaԩBmxVdggwŁ׿n/}mG>|8._T̝;Ajj*$  rŹqxwpԩ6?j(}y1cFaС?7[{NE; -vuuuO={^zuuuHÇ>fffv]EEEVE$[ov%)\+7l@999zVj^@j:eA¡G3f̠nݺ) AkF/_#G6}U[P21VWc1:HN3T-+,,˗#_.]D/:jeJi;^<'Y$gt!}h_7Pɓ4`f-rRzٳgӞ={СCZXA'NL"MF<'xhI8b!Z '*:ˈ12En?$m޼I=$Z oI~Z pttNϦ=FA?"/*A7xcdA[ &UtرcΎhذaJK={$[[[j5ee!X,TUUOcpFQtO"c2bL<R{mq{.h}J\uuu C_5?aL[_L,--^0L!/ VUSO=077ǖ-[p% :;&N{> 555sRSSD0 èH$%JJJ۷ocРAmw]VVVƉ'лwo~|QSSC۷o֭[Q__^za߾}p333lܸW\A@@1uT\1z_~%\]]QXXYf'<==kK.ŋQ-7o\.i\͛7m w}z ؿ? d0BZűcPQQ,;v SNE]]O`Сxxʍa<\+=¢%KpH\̙3?ttwܡדRҷUVя?7a?QD^]ڛ^*Ү] U<%'' D&W4n8x?87a?WV.~ƌ#|-ZDȌgE"Prrr/*8ptt_|~WQ ӕo m粗d{nMJJf&`QgΜiq;DB+E#7n>|X "sߒAܹCǏ^7Ḭx%/!##GZj Jׯ;w}sjh(8}c^.޽{3㧓Ń^%(,,L7oTkJڻwRVJXLSNcǎ]Udu+\YYYX@gmY̹j>էx "ӧ p-Y,--s(󜚻t@U_aa!ԧO)44ǏΞ=QlU̧"T&$JB~|xyVsl [nAܳ[nud@1bj6lXֹs%9W3tm>5D@y mQ__O?E4=zt1$rssI$Nű:Y<4#ޭH$Qnn.:1NA||<\bѣGu␕#,,0x`dee!..\oÇ o㚙A*B.ܹs1b]֤?aɰ4ťKe{KKKL<D?` +v7oFJJJeDEEA,cqmشC_QQQJm%>b11}taԩq﫵mvv6|I=zTϞ= 1cZٳ>L"`ժUpvv#V\fimJDDDXx1`Ȑ!VWii)f͚᫯R:eee =fHfnݺ5*v WWW… +pEmw؁ݻ.\P(2,6~zTUU\.Gxx8_yyyȀA$00VVV@^^^n333$''cԨQ´iPVVc@1|lٲA9kuRDZcP]]k׮aȐ!B /rܽ{999(..Ɩ-[mW\ZdggW\v ֨ou겷Gqq1Ν;Dضt,Xb̐7n… x75W())A~~>y땶BQQ/_T =ԇpeZgnTJ}mܸ j>}PIIll, Z̥P‡0@<4F[y0͛D{͛7 /@!!!4~x4hI󩺺|}} effzJ֭MQI$233Sx{%m>mĤٹG3IDATu Uji_??&y- _H$ /BNNNnO?ZCff&ϧx?>9884A0a/\P\\\;瓝uޝ^|ENfΜIԿڻwQU⃵crww z̸8a;TJ666,Gt%@<A.Sqq17Prr2ݻ6oL;w$wwwΪ5N}M-?7[V5JG[:yږXd,$80}]}G}hdggGȜ Uf϶T+Lslfj%"rqqvE[n%///UVݞ2x m ms^RRBǏ'DBr_~Be(22RHWPP@ǏoST-Qhh(-X*++.^(X,b pH$T\\LGV[:Vs96m䚤R)SRR… .xڢ] OOOX| Я_?aAGDѣ𷏏 ͖+h,,,>cѣt7Æ CFF1f̘vn߾ H1l0o6mfpxNZ\k.<11p@[Pmll,LLLٳн{wDFFO>pppP8#FܹsΥc!H???`Æ MwFdd$z K=l3`3DU=bRm\\LDDiԳgO]vѺuʪhOu36-hkmjÖF>TOW^AMM JJJi&,\`mmYf)GGG V* cƌARR ;Fsss|}}ӀZsF=\X SO=/7rPqOȜ̞T[+o1 "رcƔO'22[nL&CXXk83gB$ӨeD9s&7O[0leig`BOc\6vN:**<!˱yf{t "2ƉUFgϞDIIQ$ 2󩳳3jjjSЀ 8q>>>8w<==;|0`dee!11; #233aaaAA=0|pH$rIjj*$ ¡:"*,,,ƍy탑7rc9W3|>VVV0h Ϙ5k$I>w!&82 wc q!nV8t_DFFrN< |w7o:\D"?777:u ֭d[N?n:fQ@ۛ$ 7H H$& #== ]VR֮]KܜӹQ \.'@SLi )S'\΍!رcdjj*S~~>7X`sTwƒH$"((!!A󲰰 4lw9揄rF$X-!!-@,c@tes.OCttQ9sϧ) D"NϟH$~1 0ɨӧOիW>>>رc̙NS'_FVV'N;?:`͚5xakk4 6 ΫGAzz:ݻ<|ځ#w=zcƌAHHqLr|ᇈ:S L6 񁇇<<<`gggTVYY|#++ )))8y$yf,^b1E3C߿?7 ðx`T۷@g}tD" _|`e:9ͧD"ɓwaРAo 0,aZ ƍ?QFӰa'q1( )0,1<==_'Ne8+ðx`QM [[[:t/7 ðx`QͰaÐ ضm7 `aѣ \.{gHE7Qa.L\\}Yb|ǘ;wΎUbtَcx`m6lܸHMMń ZgU(,aT8s q]1KWh 0e; #J7o$"_]=lW~8s.gd8֬YW_}UyUWJJ ϟT)S࣏>#7rX`N:SSS$%%!88-l(`oQ*6l222Zܹs8q"vZܹ(Tƺu6Un[^` ,dM2$1Mo( QWC#dIlf"Ø|!uCK d20g,M׎bݺtt+OyXv=_Ov==Wr֬Y# v⦤X|yTp ~ᇘj,Ch4477opH`dA1WLLLPSS_}2> G(\~*++A#& JYY'O$))I#Ƀff~jժ矧FjjV~?%%%8>Sf 2m!h4{f,{E훘;vH c5!$B?̞={0 W-сfֆngŊ״H 555XN[[D!\hX,9s7U& ]D)+ ^n֛qoE !ɃbʢSNCEq:\.HKKd2]69ΈuF1Lׇ咀H k-[Fww7;P8tPQQq]0>>NooU oH v5TTT( H q~vɼyػw/cǎ裏x]XhLNNx 33 L&CCCrEIOOچK\+䐝Mmmż} 0꾦&,X@aa!===[[[h4CKK ,^XuJ]v18812K N># 3`x<op)z=cccEmkx^ON'ϟgv\8>uülٲ%n^zk2::bei7@mm-={믿u͡Ī/~w}7yy+#M!?n`VYp}Cwt( ]soxxI-[v9t:]ɕtdddǴZ-iiiۗU0v?̦=Mwh4rܹkakX}%<#dB` #ep8`ttG}رcM匯6 hZzx^FGG1EQAzP(qٳj\/jdjjJM<$BqCon{x<oK+UAϟO >Peeev;--z;w^n^Ouu5o`ǏxXz=O<[nUonݺ,Zyox xOIb6yjw}y,Y[K}}=Wbނ X,,]mݻwY|9^ vٳFŋ1 ޽{V׉U?󑟟Oqq1V>V, K,<\m&aqy0"Q_/6jkkcf||\݋baݺu|yB$x^!f%W}G\"#BrHMMedd$*2 ~?999~NL]\FF c…YHՅ磼\IP($ B466F2m!H(`ٷoĴ1Fl6[^BF Fө(mۆ~m۶F$q&#B( +WJh4& JYY'OZySȃ"?5%%I^^VM6IP6mjGgg$<!rZ----թPgjj:ZZZj8pB pB$~i ߿?ibn믿xgZ$''W_QUU%AF GS8@(Ruѣ8̂<!044#Aj` 9 v@!0+'~),5g(]}eEuhji!検ĸ?J ã@|Fp(a9 I ȜA9 8"(I>׿4dq0n X@ԭ%9HZ@9 >>p < xz >r?^G ,1 v:3#HXWFxuGrQ\RB{΍%Mh{IiY(,.D׉1b6z{`J7Zf k\U%%%89|Yvk}?ٕ4-/ӊ`ge0fx3,HӔ 1! h+[G, %HN `)VL:6tn3&{K;+54ZsNٙ5 ?5hjy~Bm$#|2xrxW5lSp˲Fޅ\YQy&¾)s{6bUPC‘/[ы1Mu@)<"|gr[0 s pmW1~A1C_`7ɛ+6%y`DkhhzQGGnZ"n2^kIW4<ȨJT*ғ4|D5!ДsN2&R ɜdL@5Ԙs&s3I ~}e s>ȈҪ40^ih˜AAAH$\T'= Z~5Nr)++C``14 2'A(ܡ.ф H LF`9'%%Rvsq!)sA$2'AdN Ȝaȼ(tFi$欧$chNIk59kXIENDB`bless-0.6.3/doc/user/C/figures/bless_export_dialog.png000066400000000000000000000530551374060072200227500ustar00rootroot00000000000000PNG  IHDR+1bKGD pHYs  tIME /Ѧp IDATxyMϹ,f7`6 cKv$R)h,?HR!?%5{RȘg>w1kVh}{ys{~=%%%łyxxQ|dySSSe:*!w:b6 Bq[_iJ +6QBq[ Ba`P}wc1:5!?5 F,7Dh !WfϷs &5,f B!5_%yJkXa9t-i fo}2e+!Wq,:l8 y+ {W/}eBm3CKQ9JuӸZBb2[Ld*MA](]`h`4Y\J'x׃hejeE}4[oWZyZב6ǔg `2O)d~Ќ`$3G_PS(D`X@޽QT*T*BRP{B(:/`2cE55i:u3B+isp pt6,MK/ĭ7?}uTl2CSO`0LUEt?qr>+;ok4|XGE9=-{2c-pU1pL ;&τQIEV^fcg6-CfZ{U#ZL8g4 ?TQN\ (SՈkQIf(}[-\0kIy3^{bHrO2WQBFA~@"}zebӟ) xiO0]45mys)кvW~-"vڏE3Z3ՄCnҹ>:Sסr fc6?)\xGMy͙j~⍮ndƟg?x43/uiZaKɩr'"/Q2+O&6pŶYdfXT0H.7NeR 0 1ddP٪Z=U' g~BGޚْQ:Z_q:]z>W\?^5 'b.;#63t˙gFQOͶ\/q3=5$rT41ਕirFRcǩbtx6S]79]Ne|nEUp`fxaR!ÿ4gN9C`"`2[ޝeQiU ~ϬAP9ԱY^YRm_Saqo 5:`f]l#5aW.AmԺz\7>~Y~dhqg 윚25\1cy|v )߯_oeWxηjz9;378}/.h57ة` P_7ؾ‹ dy٠aQ`(='N>yٓJov 7YGGf3*vq]3p.̙kVNZhx4 @}Ͳ* hT?\JwRv2֒`Ԗ ryT:h `«S`vlB ?8mhrqԠ. {=v-#%<UG3 dz3CdkTYW$S5٥]‚޺[7"Zͤ!p4&3gٛaڼ{ꏶ@uoW~7?3Kv$0Qk3ڏPT5 /*?wN<6q c?`6l@c׎L7}*!3~jmO~,BYQ:ZTf?_UBUU#EY*Du޼l^- .gϿl3oǒ'xkg, ݵuxSFچs?`>G䍶NdݺOEԾ݊<P3ں2r`>6 m#` BnV:{~Bqm PCSgrRvmR\Q/y1:33F].َM4ZhV Ȏ>cHKyшJSlfo]l3C5]>\;m`MegcR PT7.x2,]\ORDKC/,$叽`^lAQkLv _mT<Ħ/_Fto[jcAz0p-XT_{hkqoo]Qu87(zh*k9%]dׯӈq@džI&PkڦBܤhx-3,*5\ 5:>M~kT+@A؏Bڍ^ TqHb2]f/&}MU&}U Zg_\z db6X,(j=pthk &2j-* vnpEZule8TޝAッF]t!ټ) zX@Qc1ec^ܼ1ysɷſΰsEe|SkdJa%W-φmVi:xC𧖇n}`xZqÄ{d0BhC5kqK FT ]MZd2J0B__!D7RVbb1ߔ~Ut=ٺ!lshTQrBq{SLyIf(*S6&sγo~srɵ~Ho LJ6Ԭ]ZUl-Od6,s#dB!gVX c;x q<L`i!#=Hؑ#6i˭zzb35:T\ظ ~A!BȱC<4+WRJFF* 8s$gΜKDEGL._B˭ܰR2舳cȍY(':\bK3`b?}Κj7BQUgN'NG4Z5jwwWjgE|B*EAVRTX0~xxa*Pyn3qCuކ= 1\ŚEX;f bpi;17! C'/)ǯ>,zMm2UE뗏՛޼YkCNm jL]7stfy!ph6edeb2HMM'=-tly߁fKSS<`/6mAdb6۴]äUs 6|"-D{ ;6)lc*Zl>rZJ wgnNySj{cZkɺģl:x /u&*~fjg e%-_sk2f;klCC/W"YңӐg nJĹSBܶqR<8?碰XyqLZ Déłl!33Ls-U0tDZ*o ٺ p+W˲zmN?> x+t b'Pq[26фNgﳑnف2\5FقFe;pwwGE_ ǽ۽ɮ3{*fo޵kZ=eMy Yclo碭P˲ڝPV+KwAOdz :}mԳX9ɌBӓN|R I گ;Co?<']P=i׮fKߏFq3'u:5-I(Rb//:+I'8wf+yV̮N`!5%]{pWǖtр!GӑKNv\8VmMVCeمlx7d˃:2ӦVk¤Kbi42Z6s`S'&|tZ:Nӗ<(O1|BG_b$!y!8f\NNde'^o@ӣՓ#7WOvv.YY9dffEzz&)in.ԫSRV)I?kNEyp)m>Z4ɦ?s_qQdiu'4 eĔt }\8[t,?`D0jCחgejW\:^Н/W+4 !mڜi0Í8th,X3H%Eф`̛bINΠGx׮m{ar|te^-R6Z[C8z-Ggj/''BY۔+]DCQ'+ro_r1u7?qxJ07BBԥݬ`ݺ JطW@B? $'T;jyצ=}`(ziѲ-Zi1 B!]pTB$ !`(C BB!P!٤;P2BH0W]Ɂ|Y6w:v%8  @TEv# hRmo"*l"J*K~C!CqسgIPp&#FN6BbϮydh!$Xb2.wzAǭB]4 \jsWr*ܖZ " !Pܚ,,ﭰrlo! =<db>rG2jXZ]-Byn3qCuކ= 1\ŚYX;f bYh܄V Ԧۏ#N07/(^zMݕ boL}ؽ?4lޅqs>G^qӱ/~uu$Ӌ̀wO: ӀO/|-54׿1{Ǧݓ+_uFx{]:~ݷqqp0^h{SMεEm[SFt<,<~2mCH8OZz-}|\:M}e~aVᇭL}e8H0sno^Ix)MgR#lj< ҿe{ buBvNl]:OoGtё'Yjt"3/@/BgW2ڱY5[8é=ZN9hPpӛ-[,ujw߽Y\%ޠspP~dg>߬mz>> gDI5~q="6o.Ew)KQmkp￉<<6plyp1\:w]l;%O`g)/]܁ \BY4>e}.e&ᄑԤBӻo/,-!čQ,ک %!f-ΐOԸ^9oB{/??{Y//A}^:z>y6[r\6m&GGt`Nw8u nB]2qXH0O{9g B?[ p,f/xBepuu?S{]GwyC-忾C盛wH`k-z-&)Gۣ.qM驉e~~&e&54ե缏}o7jFׯ~<}ڶۖi4<>7\~?t#+J{ff&KޙËΒe"OOZ9F;Uby7{7u«]ػvBum|2Hw.,߮@ ,y1]^!zFl *sw8ԶUOpYS%m;~.v U^Uvyng>+@i$_7>Lt2^o/+Obߊ1g79izNLwàM& =/$#lw]YE[qֶNlW[iȰtO#&<y;<̧?{rlgxf,\&GB)/aR!n`xh,МmO`ƙl}y_G*rMtI<CYf `DONWK\i*iF~|~.3L))cL߻=wd7v X8Pӂ>}//Wm1X1%{ZƠ&?_ϲ /4oP>e-^AŊim޵PT϶bȓbr<~)6Y`cUۇ !'Q͂aq3L:!.S IDAT<Œ-Ud$frqM?L0B`6`-[FKh(C{c[t,?`DbOX)<`[8$n1hJc_13<vn`BZ`;jzA6SNIǖ['YmZMFkL=\u{&qoXSOCa],ģ{qJ/w7B\d7|ziu$ ٴs賹th_}o~rŠ/~4 iڙome|J{.7DRi @x|rjZb'TTi'<& n諾|ͷΟYJNVzÕ8yTsd%['))qNd%xyy[/33͓h(J=Vgj5B8yU)HR5{12BH0]ͪѭ{O<=Pۘl!99}{~od@`(qOMb||tS5M{("CqUhѲ *:$C!;E! BH0!B!P!`(BH0B!hr6m*''GAJt3nRceg;ۥ Dsÿ!!  W\`B] n\e.]]? wKё#{_ *ZE X}gek6HEsP"/svI@Ð*0? w[hACb1c4*Yg{v##GXwϮ7%. -t[]pwub텂aU0b%_nr}8z۷Ȍ7-Lyn</y% ! d=բf3vZf^+rë`͸/T?fKT:z;~?Ym~f 7Ww6YPHŸYP&wspP)xzsh\ qЦh,Fi,zq+7!$+N{z}_+ )6PN fױINn~N5^׷{r/g`\^Þe񴇱WQd/]ۏ+05\Hī][e$D5 27ywb|a1JE'zVz%&&2/PhX8 H퉊sxxDQL& zIH'##ZC|\ehX3sno^Ix)Mgᠺx#lj< ҿe{ buBvNl]:OoGtё'(:lkIb8yxy$OYm쮶_έ˘)^3ڳs~_&w"*4kxv2eHjfxCС9b-W/gb KQfٿS{pL2" >dddI)97iW0Muzv3gFRܳTUIfxeqZ?÷/bH߱^9K֦%cqtoχ0kC >Nf.xj}.i3W1%t~mN?>x+t Rb/~@鉷ɘxZq썄Waѻ]Xt1qڽ:[.,_8/*pD/;RW3*a^&ڕ//Z[M/4Z;rAhd2bHKK?ŷ[~gX:|ؽݛ:cyWnnֿ];ϺvYF۔w5fv.sILmعht&E!mNqmo~9]$*MM qc<8x(G%< ֮ήm@5`o`ɻ8kTq=nŵ5Z-.΄ '..zuCVV/FGᇭAV-Tu}Sm1ce+I+?ҥG[#ZIs]>NP_9 Xu NI~maNZ;qƎ%JBbYa _KٲKa6[C=?-Kcs9v~̰IբVqvvBp`22qp'**7770LfEA՚%q?ʲ 9|ti{_w!N *Z,ʊh0]ḱLWÓON%N4=m݊4V:3=jlBdzƖ?1 Y=iZ n';!nXXz^^|7)D\9?֐GS2][5N.Kk5Sϟ̓&MwxZVū'III\ h?%XX93+0< d8} n1Qdiu'4 i;/S%}rq lYб,ۃ0bᖴίObԸå?-3s1ŀ-;t*eOYpXmW/sfL3Z;ZF F ĕ+̘18jsg6X,dnkgg{g*`VŋX<R b˼Z>ͥۓNZ[C8z-GgنJKⲯkp]:?̛1< O<8i [YI uk_ ::ĩ|ko&77tz=޵|Xy?7[p^[|*?DNNII6UrrrlE;jM\g^VZӳ&]k+!}|+o?2C dQEf'0Nz=T *ll"GKrJJ~_ @Ҥ)qddf*? BQ* U5j5yvAހFfc* J:$ZtzL#9yٞ뵬FefMbca00,C=tvZBaUFØ4q)^^0e{;{EU*JVJ*ЋbFQcgE|ZZh0K.4ڵ+5=j"[gg'Q*3qw@)P8Y3? nЄU}` WCvNv~eAR[yX3\khd.(VZ;;P<<2~۲?Bm4 !#=='*mZcX;J䉓ܠ>[R/nn;8ڬCg(YFwA݂IOUi'N,s3>汢(m[NP)Z*<=ѨՌ~a??cede{5]ۋ;бC[.FSE@*/n!iGf@ u5k,*U$qιQ󾫼znj7&L&`ooFΰ2}3&J6G^ߧhAGٹFŶT`xQE` LuUvNvVnʫVk0U֏۽ 0||nz2BTV040uUvb|>%7;qO=ر{\] lШByb.TAľ=ҷnV}n{eu}'S/=zoHN$L?ZQmjyצ=},@ =ÁIO0oI08:ҴEh#!-"'+LZlGCyS !-"ȵIB$ !`(C BB!P!`(BH0B!$ ! B;W@g[Q8x8/5{eBnjbsF߯&;2B!=nhޜY̟7/~@N&kYv:!! ?$ ۏ_M[=F92Z,l[6-]<ƺe1ֶ>uhتE6B"af6puu!:E,[\!DeW3Qu>I<_:%Zv^ѱpֳȶܩ/٫WغaGz:]lxR@ęsobcd !̰ #`/Щ7~l?N76cVǨ/`WxaC ;_V i }B! Q,kwjacӵw4<{\>_٢B!,E0V3=[Ѻ/9ߚ/,٪B! nMb#;Nߨ SFMfc5BЯl9!FZ!B B B!C!BB!P!`(BH0B!\T! !wtfX:dX M&, * ZZB-6LΜ: IJB2V+[M!D6` 9)~ARR2}0˱|S2AQJl׃ͼDŽP#A:_CEq=;ApBWFB!qfhXЦCcS^a{v6k~۫s$+ٝG!,> ϸEj1_f8+R!2COSۧ]{Ag4`d—=hk>x%~9ZJ̟cS)}u,qW_ 4 Bk\ >H ul,Hh܄V +FKؽ?4lޅqs>Gg._Pzݛ7+s6x# !l2qIwGShsݽ5t<@NQ6ϥ:ҷdȑL;>@#l{$*4kxv2kiXІ'hsk2f} l%: #$j9. 0:lm_!D5I˂Ff*:ϷQQK=3KۍEF,= )36r{@w-(:=6ke6Dp3:j8zsa~mNM:4=ĩ5*e}!T "Nri XYY*1;M2q /2fvdJraN׆D٘a}|2Hw7{c{.:mUcYU/ o2ZCZ>^&~0mjt:mj{9 XJlΥ-k:fy"/fUhI2>F2.ƹ֖=9naO^yQS"9iy ;VWuBq'Ij-8Wݍ]qqPƮ km1K?Sdlo3 ֓dl>5 z sNZEB Sn"'N'pE֝t,xdwXĞ;TicV !Û a$%IJ{v5*Fa?,רؽs;IhTڡK=oG Uă ~v^-#%41- :YԯS7 !z0M6fUݾBI }HI:ɷ_ǣ{_ 1v0Q;c6wcB!*&E0z]مGǏm[&Z0`pK RKr|*UξXPڄ']O(ٌd( lB!n`l6ٌIB@$B B;CFA!dB!C!BB!P!cUZ,f łJB֠VJBqCHff&gN…$%PۇF! kV&RUTKo0o )) cw>] JXX)YY*cvKfŠsfglE䅳D=Ӈm^i*Ӽ:x-⹾g%5aTY坘`ߧS=n}é'JǠT)j 2%-Ǒ_}X;`лS[Ӱyٶs߿GVӺHddU~A!fXQ?~@0yxMyi^Y?󡧋oqxwc4nB@p+N^Lc!7=]+0L=szZ}y(J]b˜͊)Un1#O;ڱY5[8é=ZN9Tq,l舳fXCƾŨeu Ou7R̪'I }\z>>F)%yzSy~l9.Z 橃qu1 ~Sgu_.Dwޒ٘w@g/*/u_o~}:hSV_m,4d?Z۱LcW o_wem#e !}E)B%7xp犟}E[:mU_4513܏W-hZ+?#-]5f'twh]`Sic!ZCZCZ>^&~puc/GTM~_OuB"J-\=TQl4ҐgE};y0'-8Acii jw_{~I-R.W;6% =i:z] uj*8!DT-&UU_K{p߯nwܽd%ڕ0yɷ\L ,ڿICX덮k`>-e/P00YȔxk$ܡjN4}~l#]ʡ/KySʐWw.!{630u*rMrY>q:_wBaPhFRB,wn/IN'EkL&cmjk4co+D@1vzjn7w>4${?(sh5+f3 lBHLzg hlF #( t k_zM_|ʊwQǿe@$B66e**U+V,Hi)DmE *E(BY>LMY rrL5Gra4H؅]`pt:q8*=qn'"RpwN'88tHmq`aJCDDg1lJADD5}[hd:yI ooooQV1t;¹ N<ƥ"5h0Ӡ!a1$X[ԾU K?[`Ыr\N r9~t?1f ~jߢb>Rid+C(___||I9~N=վEG)Ƿ0QP/W}K]j*wKGRk #NS[Ծ^&u\t8p\FL&3&DDDn/*eev.]HN>NvV&MiӊvX,DD,ee\f8ACFW 9 5oz{nK墨/=w`Q1DEǰuF֬\O>[6Sws[ Lڋh5cϢ7OhX앢˻Z&E{F]IBم{$oXC=قv?ņ*EƔ+{lF24t9[H3NN3K_]ߒz_| 'l0+"Fr!=~J6OeX/~>rZY?zXQ1 ͬT"-b˧6=T 2a0mIޞ6o3f &agVXgNd#0ٔ$2a'gwzZU=CL&M%" M?JXxd&=ܠG4Y~۳aO UX&fkiWJU"ޖbh$mM9j,1LtsߛP/#db("ղ/9z,-Ztر(jmЀA`W_؟)k7ZPD%3#hen аH23>UnTah6SVR0nd+k7ZPDҷKR|NeYW>g(""F"Ra"vvb("c|ff[Kٽ{`XVF Nt6;˺*2޴q&i۶-_mkl=m:$$՜/YrSttYkd("7S !?/?FҦM y %U+ҥ yX}|1{Xᑫfjd("?꟫3GHJJrA#V]S=,_Ν; zn>b  %0$g˗\?5ue?~h 0oぁ52ڴ)/{.$!#99Ķ%Bm|j%:v"7' ٹs'# '. 0f׍s ,g7_;ktP+8̳J4{;w52Vwqػw^UL+MJbth߁ܼ}HܽÆ) c)~~) ^MTKØ&3^g/Q4 ֊!,z\unCp0Zg tv#($<7;{n}tkjť'lb7»Oy9HZ:m[4'(9Ϫ_e6h@WЪ%AA4 (ٕ{*"r]tdd$ƍ#)i^\̹H˖-i߮=9xyygF JDŽJ/ҙ|u5>c9}l3Ā)}lNvy 8{w-#\LUcsBcX6aV) e/7P3`Á%w<7U=O:Lzwd= @d=PPD*Ю""s$%ˋtΦ;}ذtJHҶR?:Kyx0{9tz|o#s*ݻ{m&>X1˅_8CQj);4,M^b+p x/r :7TXy0y2qtzg 4b4]u{;:AΟl2t8\EݎUN}t:,(o#^~)+xesxu\Y<3yף|[®ثG eeu*3Np~cV MߧB~=)-[|4m8yl&OG^#gwfʕDGbE6aC?ggb"k>Jz|5GqV [solbvPן̧֑SkgőI9^aJ?U j/Fמ OŅ<ѫ֯_6,>m/i0jhdXŰ r E]lJӋ'5b/0'Ob1'44w~Úup{Ys}ɘh,[D;~'4yx5K@9kxocZӇmc0[ݟ̠kl4fo/-a wܴ9qyyjcQajCEy }y?a?iֿL|EP|kFu Qy_5wB?FǵYDۗCÙ\y;vr!zOqA~;,\1c%55džcB\.H9}LӐMٳ<4}dxR7ɯMk_@3窱"3-/ywȕ{ƽyl6yXIM=Ńތ̬,\.VFߗ-fqlڼ>z]FUw: #׈+ЌSO R+a_}jȟsX<<9s&~{FvygF^ ~x>_K`` EEE\s9U?^w˯v.;NfS' "7C|222 B())R.<>1O…! BWv9ڤ"r]Nqq1%bXp`00MX':9VK-uiVO*"^݌l닯˅pt:q8 Fcd6/&uWeovb("`0`61խHݣV+"8]NI]Ya*"Re&NiI¸IELfeFYH(.,Daܤs۔eb("ҳw?>ZO@RENض QnTKXx}d[9d2$((kC:Ӷ]gq @ʺV1;ڹKN""bDDDPDDDPDDDPDDDPDDDPDDDPDDDPDDDPDDDPDD2OuR] 'O bH} EDD#â LKQ*""Rսz+ .JIENDB`bless-0.6.3/doc/user/C/figures/bless_goto.png000066400000000000000000000120711374060072200210510ustar00rootroot00000000000000PNG  IHDR<9nsbKGD pHYs!3tIME "IDATxy\TUl ;K. !.eJYZZ%k嚚%[n%fd, e\AÇ{=s9gsϽA(J8m*^Mtw@O_Ri,):G؟œǞQlt3UkhZeYV5TH(:|#"x▹> _'6Ջ]g];i֬ (3Wv$gcڵkgnǎ(RׂKa2@ s5o x&>.BWymK5۷iΕ+xh{ Ю/|c\pjժ1lذuiaJ\lA,Õ ukd l!<$#;+l;@W^ .ڜu+V@R(ZEt-Ӻ“4i_|)SS:?oѓGC^ nFmٟt 8k o_[_͜e?CL@ږ7wt=o1LJU[8hԗN۷.\%G}w(zϙB4^٣N`T)Ñ=:CNۥ7}+݈\Td<1# ĥVUhݿ?*ϴgވ1K gJc>3 wef3LE܃0͘FW.#d rIXT7h(;%QQՕn~.$)k7[݅m/ϚK%QLs?/g]h6_$Ģ -!(2 %}S)lq_>v/&8l.f[J"eU $5d3aGb2D%t((c!`B%N>_ʥgKZ\3r$$3{ڳOhq4REBPE!ITVժڳ+YxV|b%Qm*l:EYb/!DѲ!XI|j5ށ6wN]oцw_PB/D'*۝NoU-T!%B!$Q!BB!IT!$*BIB!$Q!Җ7ifX+=@RhXS!$Azk% I%؁t D)1gw'I0D!D ߙ$RARIx~efY!$ !66n"+;EQ=Z ,SEQ0adgDR5~ݿ;s6o֌V-YNHBMΟgPYJ)5Xciۍsȯ _ͨQҮmj9'IT!ʘ9霏@zdeՕI_R\,{SѣzD^HaM"++:F'-Xn==;p"0&ŔW;hcE<4S񯅜-֥vמn>[h]3^xwEAѐN%>;8i**U !\.ɶ(*rعPޣ.jA&sHau8f$99K0%VSV'ѬģL;6͛Qۗϼkfr41ˢ_\+||oY{t3:ߒȸT*qg( bO)2HOfݺ@=3{j!eE!uN&::'رcXT.]͋|wo<1+6^.88h FcbķiߺP/ZDy8^''G:oǖ"lhmUSa(cirw$j,߯O=Yz\l?s>زOݾe"!1yQLNGP-4c¸v<'Fֶs|#Nkgvn-_XwV=U d$JKOϿ !2* ZsHZ  S20g`JEqТ2Ttw"32.]&+3M^M?KPsxnd&_}|syᑎy8^FC6mhf'g̤IEcGzx3cb;x3G*T8䥑X9ĞQcvՀLCoW"$XI 2bbE;g5O^Lcn}__:*%e6m.d$}SӃOk\;>6~cš ^seOfF.7?+;*6r]GIEEŬ`21LfH6(O9fZFGvV˙/߁A`j9 iڶ;3VtLiFx5d%RacuqApqq[TÿѴi}2g[zxIt޾x |uGp`!Oeo AKH~Z5o;>o ӢYu7CE?ܶڵjѐ./jmy̆y/t sAgBj^O:'3HZiUN@76K5޷6xy,3gss0L$%́'JDU{5J %Lu#ISJLC;Y{2Ji=8g-O#E/l̳2?cΰ|j\NO"#>$iCw|1fz lѨTrMYv玤V[:':5sn[O?~Wpөn0U(3dVYEt1LRȺj3bVά@{I+8`kkmΌ7c!H:M08uCơPYMK_{WRcQ #T7Mk֨ũ\SF獓/O֝aǯPAΡ&}ęuӭzwSGit.[Ώ##e F#,cnֵp&pwuށUsaw9|yiD=s oi5kj|{HWW;\ >gFv],, v{ caߢ߯) *m5f=I*2 T`Q<1 (BW6OU'Z4L#74)45iFSn_6Q:[kj9Msx'DǼw#;Unx|v=LL!viv^}#"WdChN{׬@׉-/߱iykAu? р7a[T y&`G5>?n-5:5g @_ o\7Sx^h%D VFEl6hĠԪUv$1-tW}9OE*y0? @o |g' ]C58&CgFkwt>b÷ǫd\BTlllXx!mmE:u:dg|xeq^w鿳D5; exzzboo_[9sx(æd7Gw[^j\s%݀!=Ofu̻:J8~-Y kiZFV,i߼nfz&lXS$g`W2~Y74rz~^HL7D-?&.;7j5Iqj*tgx!]P?LcΜ@4.|<\&oZ,47f=V^OZG/;h44jٌVAVԕv0tD270^FSFArϧ{6u(O=)Z`Wo(Z#gwϷnzu̻:J8~B'E(JĸJ@ʷ&y^QwY,kt(J/!(}oaI|.آLjrҭ(R$B'|r| fV$D)'ZHV+h\'DxI1QrnIN+V-pTLT% (*7>mqYf Išzk-e&*ʀ $*Im83SY_IBZ&Nx7 g`Kes6!ޞ/(tٽj(Ybdl{L'ƆaV= HѿٿV0W1(:ܪԢC= bw,Y ռ*+9rbmik>`ۭ\5* ztFmR*2s9gjt9]a ICM-:.5՟I }},ÎFG iY~_]{r7Z'.I:N(GrFm~vZ[@֮*,dh*s avI8:CJhxCT֥d@RSqzHyG1-E]vXǍ…[.+* ˂teVY7}p@bnc[KQY|iɁf#Յys{_?J[ݰN^^$@. b~/*RU|by$Eq(fa!)|Hmm Ò44?=)Hm\/}4d) >>vuz0nYٖ"1=!Djú7(= KYY0fg{uCɚ1FA>o 1~ǵqRͣ?QVx@EUv+Vdc"νK55-)4;wSxYʆL&UtkɞQo/FܥqR>u(xY%8W.6=OT rXlip&mΗ-ohM-, *p5Wܳ'XH)4=f*N:~z78>W $oY jc%8p7LfDۄuv7ϛG[P$yfhfa(<\r-_NdӍnYʧG( "0O$i6mV۸m<1NYUʓxc+ Rj E?]WGPWW/1N"I_jfd2}h[[2`5+ K'tCp 0m&PtرMr$#?{/ ֶoX5ߺ|cU=U Gs>lFErgMg?mxpr|Sa0w-%?m]iVT5__L)^%w:ÖQ6<vMQto}bÆ_%kT-Wk{8YVZFqbsK Ms.f$ Ia'h LjI#&s.x܌& ~AnҺ [oVmI)^,+fEF R@ X600|EzN 0pwMݿ[ݷxm(;},ANga߸퓊8kBf\ޞZ/$$X]䦫K}A\qqqiRNǜ'ڒu>.s`P>׶٧3&8lRNaPsLBQy r>2E M#NSaXId90J$ ,Mӆpנ+WM#l՚P6/Bb!,}U~zwOt 4ahSҕVy@ hhj%ugDbɁ?'%*R<<`RjcB%'3Muڻ\޶F>ԗҰrYf||\{u+4IMu@ٛ QVVvq2IŨ@m]#lϙ>/{zRwn\Um>>'W!)Mr=Gldզ)T [G,?{.pM.H IW O+KHa%$:E "8P.Bpmׯ3y#ĄX1\ *Hu+r)8JbPH= e4EcFQ$ XHpE؀ϋb:eXMh P pNKbYe'bfGQ&"4Eb0$B$ pZ "b)󠘀 WU(yH"Lbg ~Ǹ$!*5[~?5Ag Y$a ][|O `YcB AM^7s"4w.Er?|@D/֝p#ej2'~@<5õ  2!DLbpmLSMS-xWKKhvu;zC9i~쑇{]Ͻy||Mӵuǎ(Zc⚾~w}Tyiɞq\]{ߪ7>xBCj1/ GeآGAZ2s<*+-~6|Z$P-0a̵1hޱ \>h kwU#AOi7oٲ( 7ܵ:{4S6tkM.~,|?}Ap˲(@B1|Mn8UѴ3}8˲II/Ƀ"q\43c=EQ)Ɇ?(bu#MǪ *eGv]q}u˲R:mJ73$&՛)`=3{$Pf(/^xInjbH*[MZ|Ԧ* :Oi=椴l\.Xlآu@\l{C捛oLJ7c1b8U^y[o> xGZڪ:X]Vz=k^h<̅i_~E ?3H;ౘ3P^x$x\.QO^^<B8weӄҿUR_  Ng囚KQ/>_[W_x1f.1Ty/yBndC] 1S0|&RZR]u7)?G^wQ+`>Y|eY9x/,K^oowMѽ2|}R>Ϟ2.3QWx!]H _ݸ΋bLÇuwmvWOtfy RABi-M\^v-2t[k&H e[m4&4.w^*TN]Z& ROL04Mp8 qg]EE9p؁S quAYwRхqc?CWO\:%q8*U]EEC\?Y-RE|\>"č9J|-˲oUU>`D3ME]N+Sp0_ÃA CS4EE$E^VK-@ .>DbsmaVÇU q%8| ??z:~x߾ZE!B)q/ؗqhļ9Tlū|mTFKC\>F>D/[|jyyi-@|\>"Ľ3Wͥw[?j4L-/6}'{iM[OB^)}R-xY:qwt5/ ;6Cf86?q!Ń>v9>/C3 E8 [Sŏ? {>u\u?B2C17Z D DK/bV4+,홗؂|\>"Ľx`eha9ALC?n1Ҳm>1v-B!5Wj2}=O}q]NrƼE->tH.MOt.r*O`>Vf 8< `@PcGFWk"SNq8 ,b/y^ viu:\)%2$0 B:=k,5a ܄H ׷RQ(!ޱi ݗ̙RsZ2cwz5" 2c.3}+W痕pf͇wu$@ȔF4w'yhD\^E{fqqyn&Y9sq_B>{uU̵<.@uJ=+W K$M|MkQ^#aiKtN+''9wOS储h+@l}Rы"U.B܋F7Mř9?ZQC )}ل s8F+h)_`QFMC\]hVWTt!%|u:/r܋ןz6SGC\ыUUő#3LClR>.w^UF`Re3Uz՝@O~mU NXqB`f,ZJ0Y -xYT~\c#KS[?G!PcWO|E{g#-7MyRLo0GKs'.s+-Wo^?Z ۲Z9^!^vi㦵kozd4 G|\>"Ľ3Wb82 e1|BB 4ۑE3R A0C;!@C#ҋb82rKClACO|E{I0kOTD%/X@C8H.#Fj׬LmDmj'y͊`*{ -^n>1i֎SNyR+VOr`بh˪|ygOTJ t)7 P 70΋bY"q0 nΒ|ӾOG؂0$u~>o ,7߸qyОN#sm I]8唚ɜ9Dt(=$BnΚ}}=!)' Mn yhD\^E{If.~7[2+y9㫇%}dx9I\+>ts?b5+.u^dk ~qxSOIf&V^_yu^3ȼH&Ē:>>D:5J*LT.MҀ-6Dq8#Ȕ**ۅr3xVFQ48;6⿨3`+EAW.HK h{w߄ǩ * БI%?T ^W`iiqLd4m9@ZjN.<c E'Ɔǽf#WQdt29bJ6 L0%2κ5o}wŷ qP IDAT?[HwW y(ޡ՞0/DEhNfGq~ʕa"tKNB$r],'i}4[_9 o~ :9'kF [(+iQGQ i^AT wT( ƝyI4 TN?ljOK3퓓n+6?9hqdj 2[˜wYW/Kvg^4m9jI'Im8B,E!Jf*Ԗ#WQk^u2BD(@aOC` ]60]ڶC}VI}~D!]ްoqr-.A[L2|P$ u:lb\,DΊ3պ¼M3u>=4[دVY& Pt?8:T$ jxMi~P狊wsR/EbEZ *QfEZN9vXt: sZu2o~y:\HnuTz"(WOr{OgN[KKp7g^N_hmFJ4l \ jűlw֨tҙ'PTəCWc^4$G\~ PDǐկ..g+Fش)/Prz #;Yb)!a& obESPam]LGbB" Xs6,{q>qcR BEqFu",Òf%Uy:(amdUΑm#\S"I2<+s4Զ{DBY 4 .Ah͆FsT}Μ8h2' +Η }jzͨeĹĖ哘@ T(* ~dPM7Eu+ׯ)^K vY̠RF k7O, 9~8tfX_ 0a$RtJ@B駔J%~v28 ]JIOo$^w:ayH. 2 8׹p-O/K3dfg)wc}~h賣i4>!%ϙsm1@`pt $E}C*/O?ljJ]<3I)DsY^JsG_4Ju*!v F`o0.)83!ܹXD_鷇L::5IѲ%̶L9m@ 'Вl=)BjP"5kt^[P vwօUE3'+N3r i98ΗKn7/۾iYkmՎgv:/n;F@wkrgXiZa$&( G) Rf`.L26,+3,@gC3]'Hw1HJ*PMOC::1OIR4 `t(6Ba2\&"Hskb10CC9ck3>?2e thdxNFTC9#nx<`Bvv@^FB)xU^@IqU,Z'Gռ9sĉ\/'gNc35cQiuiNf'q_+?8[JOhq}toϽqm/Csr=gzMÎe)jz}yvJbL' Z4erjơOV[Gd& bD*Zbale 0YyrAjVLι݃̓Pʁ&Vf$kFG['#)"C9#V6v[Ԥ JA#Զ)ᰟn1$KD55/ Ԋc'r9ríǖn˟͕'N0|Y!CFUWvy23HAZbmXBL.!r#r c(,` LRѹ"5މGf壏6 jexa`Xr(X41>auϚfNN8~P x}sͪcZktpr^*IV-r+eTziwxqW> "۸ V65mbˡϑm ?SZhHP2B-LΛV/LNRȪܴ]WrR*D2). J3D^NΜzCՈΜVܿq8QA8s6,tӰV[ xuɏ$\srUvfhN]Cf}UmY ș^,LgnR0pMPW3(eBA&n?wHl4l͙蘆a0nsx(mvw(llRM=67.r{Zoٔ;ku9`mdWZ9iD9׌ m #r C~DvC'Eh3K+=qzCМgМ9rAJL-j4$h)Zu9DUV>|7 :yL˹ڛڃWTTTWWWWWBVԊI)80 K%lJYV='{[l - 55gKOVV{icǎm 퇪sR;zVrd_mh/D#PTC3M]3^t:sNi[iX3a@r[ wf>?I]U[yv__2&) ;;M &ZnGe3|jz  *W#T Qq.o)liKӡ/ۏj@uuB`, ̡,!䨅Xʞ*0C2;%8YI)sە) kˡmM {X-6tyYBH9wq*k =1Ɯ﯂"],Hh*m9m1B|ea:M<5DQݼ:ݳ/H: B6,əg_mӷaYlbx5Ӂ,7RK/WԇM %@7xϽӳSܖ ![ހ61N۩sC鍃OL8tqxS8D@Qz=a>> ^S7lٲq-g{,//y-塭䥨Z=#==mR0WKY/]C3%Blbe=-Fl_֭_L+-HlWUE֭mэ߄9Vu>'zCqRVC[mhkduR(t3:' Qέ;f8u>$ A[غ %E L[Z16)~%IRʸ2x@]9mT eD:;R)ts7@ -8.v41`uwk7%*%X0Y*7 E8ytcƾQF4zk(@N/=U/CIWffrJkGvlV%k\^7v ^*ڇlABHąZ=I0?=l:-_\u]w Q8Qkb3[e"B L?fmjO0hn#¸SSI[zRur!aX!%Je.g[VѩCz[ik$d$ͺYsl玖^=,QiÝ5vqϽJ*1q? 02Z ᏠJ`tZgB&/q4nJ+8颲Fu]) !bqa!I-kJҨ#|6vZsZ#뜜_~p'] -pϽ ^)w|@NUWws->G_تX 2 /n$^4ݜyqbɭD-ON\4P(N(:dYzv2R9t-2xk ru 1H_gb3/o/1M2 hKJ%%`<28Q9=tJȖ}-y؛xٿ9qQ$1 X'~qα q5v6N<NJxxq)ŗ]}?Q>t9n8[U\9.enet᪒‹/$ae"`ȸ׀aJJ;r;C3#qC[^/.dwU7߽bKCCE>XivCCaszxx %fVo6ڸހ[H2Nn#ǭ΀ NAkՂ g\E?z q9UyFi^]r3@=̬E IDAT.tw?w>Shۦ7w(L\L|ްR,MGo[H$bmRx7?y;ʞIY >{lX sw!уoCXAKM#=ߟڿ'P[ =cB8>ey/g0Cp#OP) JGq.|Qx)]xyp q -i\xwvo9g6k\RiTÿ ޾w_ z#HzM}U*OWfdQXϞ -P{ NWBFgr@~[ouu..׍.nV#TYqX cˡ+JKz}|8qatjkhF{-kwٮwvfpVVל>UUXmW^ᮉsuZ#ǽ.z(_sG*rq345@uHv C4r\NkT1k @)ICHsRVoY- Ebm.=KuY_UȔ):EKJJJL&(\a":]*ADm`i@Mk+P fR 2SEPWL,EA(j p8@-RPX&ܢ&m_ %H%Y$LK] Pr: X"U\BA! Y= d6 9׭/E¹WRam nҙӃq9.Tzذz*g E9C^/gGㆶ./6zk/q/yy _rarGKo7g\o1;!&Kkg̩TWgs͛Ӥu֎iv7i02dg[˙v gpDZ̸ѶrtV 577K WUU5m MgI@U5;q',#U㎩SN8S3'db=Ssz.*iD<֑-<.x0m2 篗75B~:~ݸP_ ﯫ;kkkFG{C}K`6곟=l-m \x#{}{l6oShs}?>tp# ^xJyЧl&ܶMSpť<}O=Զm۶mSOqZit볿PW惻N>l1ju? }g<vWAi8 C#}y/غo>"<ǜUG㕹('rhz}١U\LbV''`ˉ).uCφ.C=9ۘtzw>{|R$g=syS=[-!Y0^})lN>pYIjijܾy8w~ AZE)}}0O$WZ#̄m%L\s}\\\w}rZ1atB]sz7o鞭".}]qZOX?׮.tƎpp=pz1ʡ}զ`O>Y\\kk[in2検BlHKr*.F3y(늡ĪF 4ǷCB1 (h!ip|{ kꓢP\ ]=p%9syPBWynO}pdh9)Iu5u'{%87.TTujZi*PAQ@Yg؁#M`q`s=<<%"hX@F0;hE^I|HF&VxPQ(#]W% ȑ#[vQ*oH, \,xR$ID(0g4S]Zj-X`X8 ȮzS?B*-p8kVUFX~U=Bo m\@v ޵*ʬC8ЋdC) T{Qj>~ط)?haI@F= j~yի R 4Zܹl 8UZ;c̙3+K>j٩~wSmeĀu`3j{%~L[࿘VQb.W7XQ% >6RiBZ?qO`TMwĉX5*h\Zl0 Do&\ 5e9ƭݼ(CZH*0t6ˋ7C"_icN)w]^!V pmɛ6JRһi3 lR<Z2cm´0{&BM%x;0jYN=sf@og8a%+S )]q'*qsMXxkE%8zcEUnAA)B @:Nݟoe7DdzzzZ8%EDU1ж e.^hDijk#?+([hHD8{#"ĆK)&4/57*1&4Ξ-TR>&6FeffΞ=[qTK0{b9paᤊ5qhV#5,^Vnɲ5twҚZY1f e8 Hf#q%r-ސ ʵA/_<C@"Cc˪ʊ]UJk/Ս9EX5 b")kog89ev@z 1s " +#>EE[B^ spHυ/c&U 2ٹą璖h^x6w'?nQY{I$ Cjh{wNR7݄z 4xw.ͳ2hv.)|v߲UK 3]i]\tr8===%vm5 )ظq#D}ᴖ^oaHϟЁ[k1%(0ƍ 8,[ +W@ dz*rӯ?xw]iJ\tqz"<8(Z bC]`0Q=9!VIm3'x@{mYT0XfrQmbT^9C&գ⪇deEIP@UXżR3BZXST\PԫLQ֫yq;MwY1|mݜ֒c9n(AAA[l65 B=BtGl]+|.d߹n7gE,D5A26(+ւ`|M(dz޺My/#}@,~ p1DGpPimIwx$N6{7gn#ƪ^@׋j/]>p~pSrϮIe"5A,"Pt_^ _^)WЫyvj nUv$ l(" KGp+_d||4H+H$T͘bf:JT#@IAn*Fp/83Ԩzz5ZG.(%i8|j GymR5Lw3W`T`o`L*a3%+(޹.w窲k:!@׋!cy%eઇdDeX]EzO`"OQ^';si\D"hAL+Jyaٵ;ʣൕLFbPR1?jռ`C.J(9 afq @*P-yUn?ສ?,}U1y@Js޽ykwGp*/~ ‘.CEr||F*v2+#G?{J%AbdU+" } < է(g^gʀNw=D'ݩ+,ח%5`ffX5Ɂux6}O """&Nh K$RltDgi j0/78~: 0aDDĉQz#45V0TzmFLF8X]Rup?.j#7/76z$ .UF+9d I™y |:E hJ FG>V]( uf FeRkjiE(ݬUr՛^D1iAIxF+<#!FlW}W}"xFU ?qg5gK kn[Ët 9s፭l_ʎC`e* ..mK^*Yx7(8XP`l峀Dԫh3b2FZT*7#ztL!ltDKG%L X=A=l60wZ8{LHiW+Zj1ziR)郞. ĨzEӛzsƢQMpqƳ2y=)^ _^)z՟)OwaTs8YwjDjh0Ts~Ts@@wuu8tʮ"v%Y^Vҧ{LSE}&!S^v,Ty ] tq1ULZLT e޺yyy%%%%%B.PP{*EPaUeYqikg{SaaaEUo6ST_P\ هTRTUP\ |1@g;BE/q:JIt:닋验F JzW#.Y1jUW9 jUvP}< >+K*O(lI-kܮC>ix]޽P82^@i >"~ME>Dgb1F`S(qJJd$zO,xNFejdJqqJdj%CYT\xء_ֽ}6ɬ+zWj-n{'@a$^PXTBf=wD8vl{GgaZ>" L&UMYlHj=4SA*c' ~jzEǂ:<2L&We4_"q ۀgix^/bT}߹6,wݰ>v¯kB06յW"_7Nt]m d 7=㤫~ &(#ɢs%y. , d<@=hF|ϔɓfϝY q1K- \0NYԂ9;ݿĉjy+WOW9ڽ+7 …Qi+7,_aeZTw*+2]QUXlo' ~ӧEPշ׍L166~uFz:6v}py8ccGW^Q5"Tv_ @po^0h_?Zt1IToalt3f1=><:2꺄 iIݯ9r_|3C) }>``I A" 4\tyHB5kh`lkr~([0R:::R #r !Xgؚ_xMMx6v֟twU}E(0hw@UJGR 47 `dp]߷4Z>/Ν$0nb>5ڝDž}p0KR/£B= ---tNhQF;x(-۶PJr{?{N+5- Lz{X^(-ظ (%Upl[xu0kߢ 7l^G&Xk[kCeA^rO"Wsj`u qyVNT]7'[tM+x vݝnnwYI[LWsDI9p(2=I/_ƐsuGZb>>ANKMM;OuLK [l5L/)GX+$U{]B`.J1/VuoooawK[V7#9߿z)Y^X 13RU9 _3VڸAu(*MTlܜb**nZGwWߎhGMljJtzE Šu`DTYlnG@f| @m 77ܝ߼t&S}BG9e+m4R*A᠃;ܿ Yt SVZS&:X׋U3AyvvD540#^4՜>4՜J"ixTs@ Cswx,>Q^ `0M`4@\R~'m `?D ` mLm)1TUԇGJŬR*P0b(7xQVāɆbZ|5ꁘ/ C0 (%MO-,3ƣ%utuWoym`?d@(7n\gcUT:?@im#wwAWBj,WꣂU^"%nL'3}QzDBʽz+lSiFj& 3x(L![`ҫW׋]بە-ט3Ba-lT7od0vرc"E8}`X<.nH$yz5K\DnSOgzQYcvPh"8m}vRctz}}}`eQ=ߢа8,pvU0 KµHTҋ3dRLoS}Չ3F*/%K^q;/`Tae 3@l -XfgW’z3#6%g 1*mp%ow@zy5 ewڵtūYāE Q}"VTTl۶m۶m} U/QP177365612`ʝ݂>[0ݪhB{]\( A.uC+X՟.klooO$~(m9zF |ػ&XhZ2X;$Tlwp6Uu?Oh?rh];5Zk!+aUBelw m 0w߾ݻGg,jm#'McpP:z0Zx~޽?O5OD`8"ۛ8Uf.:vWҋ]5Kjka9 _z:ĐrzW_ĉȥ IDAT3sKKKs3ScC#==]mwعphP"28 %R˽f\fh؂9v[lt|v*@t0eQ6Bvش\>B0Cy<T SpDD/G"WD(Ga*GXeC3 rkDױ|zi@P]=bA }s|6<~YY}*%{6n_k'NDW5lWyDlNv]+thaMX;!lz\XXhUߕmmm#F>s`C ` '̚W.?"C ^*Šy>O+1tK{'VYY)2pVѾ!-X f4 7WPnÂ5//^GE(bjXg*.S3;#C- /fx*hkJ05#>ҋȫEЮ^oȟGc$+/޽{@<_*(,K]Wϣ3j:;W@t8qq/ҕ&&z .\`kW4Y 6w c;b z/E pj[GGSG],(@b, hv9X k Z<@,U?![X]Rs'$, |钥Kp.VԵv5]fsAHF͓CL͞\UY0c$h²oCE*BI)j1_z2[Vbut 3H$ݲTL)kAG "xVW9Az[6,t`<KLm@G"[kꚰ g]"OTWZXZ~0yRgg~`+HMMj5\\6GzJM,+ QhB:BΥ = g..DoCcVVQ׶3K%cck{(vB`bahP(pww1S" %oBât@"tv0LM#'jIxgG;T% 42$QlXH|~3bI[H$KK'ݿw; A,&P"Z;VSCxBlVmjJ ͭ$3͍ՔFSL&Bij딫SJY ]8r9,^%Idopќܜ_O\677a&(J;W#ani3opڅ;|psv9T|ܺZ@*inlAa`kT\|:gd657UUM:gr[,Tujݹ F5RM@Sqڭ)W&܊$Yjݛ1i%ϯG% KӯG%e}84d@P J[O/_XC-\FeDz e?}wkc@dX{ Uۤ]g^EiC~zZH2|QWaUɵTI(4w:s(+@qɕ5/iw1P6fV/wF:-.m.1,)9e4mmmd2E$F_ g$-\fjRQw߫7YmlݨƆ1W-2n<:hVkE啒 (qSY0IZ+IR'߅&nK̴DE,mtBZ˭˷9t?s wuY`>?qj6#~]3i.sxBWIj )"'QhSs<\_XDe(M%3[TYxM*!E=JA={uШLPv](5FF&&ΎVEeV铍LMLd^VVյpqv..=F&}x%&.;baS[ tFFF}F &χқ,m8t̆JX8ۀ>((.U7u[:{JPVB:,zW,RǸI6ptqg͝9K0iҘTcԄJ.JCqaok2L.Vvz%zSeGTe̅fF:@PEr}+L8jԨ9˖YIYyӼ_l}LP&5|YupU R3\-v߲< Stt𮟞s;Nλ@Ի!y(_WMQFzsxq8q8ܻO['jHeAzan\ "\5DSAфB>x\=[7:-m Q< +}عX]̆Z*QawY8kzw0 嫅}عUC!QhB9Ԋ@ 4;h^\q eddf H(6 g_TNJLJV#zr>;p^NCͥ ΄^.[φ=zω*I=zPp @e{ 2?}gi2>ż~XpOXb4] =}COoNJS+._'O[,}ZBMR?#nswo(>&F?x= -ⳏ߹J_W@ԿN:tbZea!iy@. >r{/s/fؤ٫描2Nq }gC/u2?IPV[TشϿucbqÍsKMX&hN[w|oW,/_9k3iW}bZaaƍ~~i.: |3Ēsa1nR ڻlؼm(;? ZR qLe:K p߹}"83.q'N~tL)P\T|ZT:7Omb[\ +XV׶i붚St<3Cn?ڱ ] 7opᓭ۷t Ͼܓ$z|s7l%%uF{yߺ}CQV>p};Uk?޳<7⸏yiOU;X$I5wiVtNll:ZcZfcomkatrZ__oR yp\ X:?*~?O#ly vwE>cF):n]zlWp1-pR]afB(rgLp.$WTu򴥳LX{N֭AXF"=w^C(a/A_79,Z-q܅;iSydd'DkZC[GH)S<.D[mi O=A;utABLv>x,fՖϓq(Yzzz/DMkF [tp›/="~/YK;Z^8 ?s~H%%%qޝbg}0&9^ =&θ|%+Փ? "^K6ɼ a7QCnhՊx DArԊx-wқJ̛h@mp4]51U[8IZM-}r:QC"(CPOYXɥoR)QW4D#AфBԊ0525 4DiB8T Jh2zJN.(ZCԻM(_-EjS k3 7ZWSm!P &abwuƿْrVve$ QbP4|PjjEhCK`b-]}]m6M$f*gw1_vvvt"ss3l6 sUd$]|I@*.F{fNFKkH"f!`pI.*33m[e{1)Μ imia2E'N鲓Sٰ_Y|8н{#_pm%1))%i ! [Z:8l6ĩ3r7ϟDF>zƢ\sW#J,] ?P<!VVVyǎEE? WUFFE}رcl\Httw@;7OHxrdpK,f!<@'*C|\Y;=.µ[=>%Ȱ|PT19V|K'/O̬L=s܉\_i窬vp6}u =#Xȍ؇/\ p),A̽ Y! ]N>}}ƏtY޽ 0:ZRi?\)" Iq/JU {|jup;>ځm۶~aN3f͟7IֽyLܓFswj LPkdsL--zaz&~急^(w19k!xbۨz3 wGq|>|E-zXnnw@6 4="i[Unȕ;qܺ~Ewy&ȗi~?X־~= %`w6u-l*/%"Kۯ{w<3Ơ%ʷs-ZZz?9%;׻֯_/ߴe'4-:>K sĘӨm^ЛX[-5*<,V~pպ_Gf*XnzV(A^|HYq׏{,n~PkKn&/l؇zlFݨ#F9j䈗 Krl>w1f٪@T[trbĵ䔔!93|?|dsȹz-ebdH%lf@ee3<|AkU=Ŝm^aӮ=.9d6ž. iڽ>鳗؋@ rS$1ĢPX}O ,Fnߺ_-vsj.W+D>fZmh'>-w#r_9Nk[VHod54[پ$X%Ⱥlim'MDܹݐ"ƺ hVK^uI{b֎9"pJHN)Yɑ@+We"Q2 ܆Z=c37oC ?QfnX,6m$$$̜9SRURel==[;g'~?b[(puue2eנ;@2g 7&,8&.)g)!b&Ƞ2l6jnn0 TF3wpN,06cӪ L^)/[OGI m)y#(>`~tZCAQ~neMŋtDSQ3[8N @$xMk"V]\L9V㬎V2a]-"Qqii#Gxttvȅқ,m8gV[ԕW 21uq{$`^cUKL:*Unb&uY:٤>˞h>,t؉:bK173Y,;hTks0 d]]]]ٕ6kkkEf)hٰ5A ˪tqr RQQ!k#d^9(oc(%%5z;Z wgPK]GXHYb<dy2%%%B{gғ"=5SЂgOSx۠3/N'@e>ܫ Q`t|ro4Bk@cPu<3+2+3cЪ\<* Zd IDAT`hUyTyor3hz6o.`0" +  f][yDi p{q^@xJ|p QbP4|P;wh҄_ʍH(Ko:4D_(KB[އaSʵuoR)vE4({B[އb̄iY4(B2ZhЃf@ >)9A,[fTqc}/.1mY554{;;@/]o=mS^q"p.yzu :X8p 999q,/vuO{۵{n^~VnRH{\S)$NDX檢r"*-"SV>yfrr2Xk$>st|vʕQsBWWWO3aL|H"\X}˦h/#o?Ry;p>ٽsGd.RqD j{G233w_LuǼWLzo| Y!233e֕Re2o5 `ۙR.Fwٶc<_)buǹ+V) Gěk6m bRȍoc';?*͈n^x6$$"!S1psg]@"Z%>-]omY۝ Ul+Rۜt}[,(,r3mӪY"cf,ش_Qў^^e<(c /7m4L ?ٽ,B'1UnܼeXm}}K.AjȷY'O{;۶~(*bm|X_N0~W?xg#>G(txE<QýƃtGf̺q>Z0?>e/>p\. `loKJ\8sAguqa?(Q(1@"w0:}**FUHIIr C?ڵKWXT9Qyڗ_Ǐ[;WFf։*hv@'a'M[Ϩ)w0R1뭭8?keP b[ݧ;޹DbT N#` DcG}rZkQiiEqíinEA\Q&챮lwںYkrL X,0 @,b g_iJRD*w߽0wN ZK1pFҀ |Zc&ߴq_*gWTVTTQ͔C?ӯIw{EE'o2Qn&ߺYTTD",3nܸrX|>  ^m[=ӝ/wG)JϿ "[sQl+￟6mDqGr}vʠ]|n{f&ݳgo?|tGkSmq͛6 7tg;|WvDlA Xna8~~~~~~rKdsrrV~kgiii999Gݻ-9/()>=c}4h~a"P*涢wgL˲uJy[Ɲ4/Z.!v/kʉo8!4"q4ndCa ֭u 4$Hf/S޶4A~僡iSCTJo541Z~+D i(|0_B>">r?"B "!pe2@9X,d %G;&39P8.HՐ7n=^|@p<^Η.^ >{Tv+7/x\.ENy\\^r"" Wơ 'Or|$bqw|Y|ٜ'{J\.Lx\a'pTѼ׍W}_&ԉnx|jJrxOHly{>u;T,Z(RD,Np8챯y,6[=@<.f "YLl}|x׹R)X_f\^>]Nmݳw! ,d5: n=>t49綹+~}׷='VԴgY9\/;x3xTB#ّ߯'ꡙ> vd?06`0qv&2QS&O*+)~T^>wn3gvUC+gxc"եcud͐R݂BԴgrGvp_ U'ĀENn XrOE>֔e={dgN@3g?ݳK,vBrBvtr5DRi'ßago6u+ҸmI)iF/f.N-޸u\q|CFo?վݧNP$ܹt]J,..o?0jhZ_C420wgL+ a6Ny'qz!|͗_^=zj$!cU!u]`ػ>]yTy)R a kȾ$DQ\iE@{lcLsfLϜN>Μ^lkV@1.1BEƾʾ5¢DD|>'@{wSU9ܻ+##e%+I"Ř ~K:?"#}ou.d Yjo*ev  [nSPZ#{o,=Up+Ի>oEGzW|I7DN=EigX՞Oqʦ ˩`=5UЦdx\+žAIӃsP_Keny 9 Wve rt?^zCxb k54mC讂wB¿޼Jm#̄Lo"e>c@Lnk5 qHcԁ5g{׆ 3eNX-Ζ-РvH=XwWv]SW\bvjo3^.N ddbֆ~ .ViҧO= AU ^c%;,HKߐuɽҰ{".9c]:%=C=cu{656V6՛5jF&Y{P]/wod(EͭZ[kxF.ٰ+9IPusuEQt}DI]H2/[" vZ"X0;?Z~; ؙ@ܸ~~FMtsuX$ٷy˂DgPal§hRYaʇ\KY{-{B(!P7148| B_W[]WٞFxG];ZQL]'dͺiàϢWvlp5' |Cy|& ;1ђr+E*CȈ0,lڲ[Uܖ_/ <₪ { *X6tn܎m&b-sVV0XxCDڷ"{Y!b3jh`?7ae&d8@Vv~c``Phm A:;? &nki*ȳUnIൌQhH{G1Z&M+wg7o-/p_`灼xs~3a [0"uڮ9݄Q'ZR;JyYzE|g|S'Q^d7ܮS*!4dqOWL& E«o~Kϥ T@/zo T@xathh aJЦ*`0^CsP,Q0$NU.:} FDgbm`\(Px5VgCl3?CnlXS'[RyXl`wFft7Ee~~T*53+L:[ +{{G[^JTJUP`2 5NJn ť:u#z.gtެmj["TV)YQ(U\gQY 3r;|}Rs*ETPh4!" L|Yۓ!3&DQNIPTZ* vu9=s# */Aή^7gIR\=M&#ȋcgƕK)n17k?GMF9q.]}-bMT]LPL8[oJF]~Q&/0 4՗3rЭ*ձc&e-iOH =FRӒuEIϾ5:zepb4/z΄)Ujd.&]N& Sںf~; ^O8o, _XYZ1i*S5*U];cc>Y4RgɇIb oKJ mJe#ܯ([S%ӥ)"44?`s7;ƌ*PGD(+Ujŭ=:#.#ͭl0|\茨ڲ|haP/ȑ vM[6Ko  @(X,+iQK&bfn5v=&_=r}JRp%[8-WW+~SQkPʲL΁+B\2&{By (3 rr@lܸu{uI!Q'[\zr#>\'ﰑ^? S]p,4=K>}FnPe=S4۶I 9f!S, ⩒!ݾ)%u)9'dX\=KnbujJdi2T7egmX~ _Gfo߸Y$bw1L3&i5Y3hOaX|nqۂAw z-E8a_yz{LSQtH9yEbF,K9jfne5wf=L&B3[fN=(s]һ3n,̞N^;'$쭩(&:;thnf>H"U2]QKyi5tG&KOU1:M9-)Uc(2`B ;ɵ4= S0a/zW~܄}{bbR2rZhĒTb,ps$&9abRg$UѨԚF^Hv&H$Z! FZ|g3b܀S0Ky1[d?@ͼf.N(QtT؎K8XRO+kt "HN0gtIEe?:Db/ tU_*/xLaJC}T(߻٦=k+mj3Y9vj#6WCboQDcIsɹ;FW͵}2JSO_ AR\W`h>/!\qf/l>Lst6ft;lO$ inlT7_gcFP:BpD$1 p Ä"_HG$G$<0\$K*Nv "!} K*"1| <^cS aLVOGmՃQ(#&&uvuվi9@H0qk/ -+_5'; v,aOk?1Ͱ hnjg2`cF1}ֵCg<{*7i_$r5-'Z4S?:EnҳCx 6&6aζc˗+O=1E˩ :psg嗎w!r5AnĸT;4I\rjeEӭF8J20~!7oHb3v`f3~@ؘfps_ ici/$h%4g͹KaH f?y^0rƧg.pD,c&qPx/.n\*Lu.),0IGfM^2sP(Hk eUUUUF:5<=e\ 7Er7*qb"SHMHI1Q7{m34ea5ZX[\V>hC565B  MQ>G9"*qb:%ݾ;(bKhy_pJͬʒSG{.:.' uE4h9G:v4'iE/[Vh54p* I}yAwk D$$몫 EbnXIH:\n]QeanAY}uQmSZI/zy },M s`p_&8-8nމqvvQ3&TD}MD" $sa"Ha"HBr\ZQVaه+F,47 pSx+~u.AcjiW3`pV57xpԙKL:4J~U}sscjZ;dOL|aFRgB T!+leaUȴ -%t8 /&rH+*LESbo.+Ջ3 l˞kpZ@U3E3\~*bgo7ceW0u4lX~I8uut,kkP)ҐT Eݞ1fXGYuf T}Z+DX e~Ie& dFK[Nniy 6M-4D~%įB!aX, XhxW$ qŒEP$8;%mxfeQ bPpft|OǾh2,#abM}0LBJM|,bh<{IL{<)U4-95d%=Ie0Yw*ڦڪ/4 )=)m3D$QE~rY4Y>RԲE&ELӢJ$#F<}(ah_Ð/8x||i0/eU֧rI2P]RXp+XeD|z5扥 Uȯ|),V]=]{h EzoUY\bZiܗBd6Tk3N57D^X٠pa3NgUr(`"~757KOUr1 kh-+R\5:f"$穐S`tJ&J5@A:yoИ4:]H1JS TF M _P1FcTQD|@@RJTT01Ɯ5ulinFdJ.TQ47Qit:%6ѶæWP. )T*"p 3Ub*& 4:SE f Y y4XԌc8DB J_W xbFW0a(T TQyPiTDR"!1!`ESe* L$MT*Ä8ә*4:mL,(tDNЙL4>.UX*W[7TbPلz ǛkLCY&onLX, KEp[Wb~Z"]|bv@  *Nѫ3D{j]@tw耦.Ӡ}!01cb|_\RǚL94ځѡ#9 l073 藍(Z)ᾷ2]`u[i3uOӄop'=KZP= A JBQiX;\N+#F; EBi1=%/=uPpK{k7vpĴ-8>#uEvvƯk5}k+=o^hwfE3dqӄcm3hTi+JOKyE/ZqԱ2a%9GU yeկD[g@rK9v5^5RD g g8r8c8!1 MU5*uyзrǏGglGh;G{:nF5AZ/E8v521=>’[32}8GY̻r mI "0' 1Q#.^x5+ ~}᣾rJ i] H2a>GU@tt򨣽K@;QrdO,K%ԧ/*֊jq:}Ǜ4a:9L3ztޕ >ZbȐ>ikIZG&=EȀiS?iPitKP ^谯rvzO`%%kd;Zkɛyh i6갯r/@ a0ULf.>_ hFyA &SbrK(75"Y5ѭP(  ^ӘM yd:e'NB mrKHt?KoNt@((q6V|T_C@ \ [쨤 9CΙwE[VBT p^Sӑ7nlyJ @((T8$=ra=Vs; p)T4s!=-89ZWQ8q:qB㍠oo dJ * oƢ{nP?z._Ų.uZ_ء ێ~Mq8"h="Y_l Jq4iB$@55v_T\g~')\RUMmy}>֦qiᢢ;wmSXo:h=c 51uy.Xpcf-Q}שMޱcԑÇk}Ч4SnP_ɛ8RIǺ8aQ{./}O d..N|xe9Anxׄ춠!걠?0) eR<ɮ'|uqtυ@ Oرc'55Խ̌Ψo\^J pG"D{qp@dػh:zy٨o榆FBoPQy1yyyyzz'!DG"M Z={5p ꞫIʈ"X$D"P$>$[2ߠQ]QfwۏE6oJ2SJTT+DE WC]_m5]|e#-XAVdwcNjrN! 7 )};E=M­XyQB} bBڻa=\EC@G֔) yŠFr.966ĉ-S(wԜQ0'' 񏦮ɹcU_3s4611,..1 KK Mbϯ$.* ;8\>}+M [nX|(KJr}}pGZB8 φrs+-1!7|.[)SX]G.+sLH{?]]]nݚT5e 㮮֭xRb޲ǎ(mq<Ȯi?o\1``䃋g{l0oz^ބ&"ܬ*+y)d%^9VSQZ}`J`a+OJ`/ 0=;7[nX 1iz(,'r#ϑom/zL 1e ]kSzw\ϝ3!3/9@E֔) # ]Y|OSlܲĩSd ;4W%T5͛y2sj/|fKX ISf.[ >1+Mbh`ϫ@UVSL۶%`87(G:m/[ xz`j1e ]tl} =\ϝ3!3Σ@n$ƍu~ҿYZ?3ŋ/cg{,5PwIXys^jJrztjl현c NcZz"`IAfj's?lwVf 7 )n`J4e rU,g}H];/..-=c:r7iZLa <hZ 욘9>קY̵tmOI=wnqghOӅ~˝O_bP8pɌ5oOI+5 ) eW Kf1{g --ȬB=թdzmYUM5t}1ˮ%EՕ27o=@@Py\z*q @ @ :V< R}*g|Ѯ6$DJ0xM?`]<#=3B 0ccts~AbAŶȚA./Fn-^C;/"j5gK ӿN$e3<#$w0ukkV+k2byn5_͙V^WԱ/6x c)ќ g <== $rWEju CLay[纰g.۴iJ㼾 !5LU5~.xO@̅vE gNRsƄW/ 8S+˚ - Q 9v/Ydll+lR1# @F: KW#yAcG& su3K 5;ۀ :ă] ׂ|rJa, aa@q-rxmW{,}˥ړ,Q\g`L}@?Wd$s#L7@Tr=ٳ-2=Sh߁]? `F^^^`oooooO݀!oØ*3\d cwP ƌvtpt$A77psa#T6ï_ \V0s$\&z&Usvsssss6fU6u7RoIddd[Z0IvG[[{w uTuuunV}VDwyv2dަ7 9\8H/D0 j3p$AY3:+સVy*ʔFC?A!7[ @jzϿy6>^d\1?I$Yq$ ͗mL9tdz IDATFn#maFa < eO6%yw_xGb6eX񽃣˚Dp8psU#/_ I$('k=y㙫Ԝ/x@o?is`Wvgp_l9y` HI,6)4 I 1O>`V8Uq '4A}?ot{+DOh 0K lTYZzc题r}=a NU)Y֭XZRa䫝^ZΊ{|<9@J5 IwO>#ɋ>~@&?vvv\.WZR@ݧ_Oi"\n wosp;y7:OYMG;~^ŗ5 tLW 5*j:l6<=6rS*҂40E~c8OÉ3~^qOhLuUh,--:2eb }%߰W*n @Uٰ`V]WO+AAM{Pa[z&Ws;ڃsѣJhЕh' юtE[%?zR\mxA SkTiL[D7g|Llt%c]\RS3W#һSs5s8p(Tp!1ta8uTHNnC# $6;ֻ^Bh$A.l6n@@٪>7\Wz3T<O<RY` fFlLSBRع\ul현c NcZ7G@]1Ā+ d".މr[app?EQl1¦}{@ P ^p? LAQ' 10 TqnᲯT ?\<_<~70~pɊ%U>'pip"##+rWGNxh .d_܌Kx4f7}OJOx2:~hI#y\ffo\.XYK۷/==asVVV9i.]._;-= Lth3EMEoTWU#' ]bR 4a0Ş1aXQQ39-=p{{P*A\.#:eN!f=؞QGNxi ._lllVV Wϯ$.* 1'Og+ܺu+I8T槿b驍AS)'I q/?.ppp0>0<}0/k~3IK0<8pŞܢ:^Se;:)YQly 20#v򘷶A{=rҖ'< (M] ?|-vꦕ >"]k|==X(oٳԽSkhTcB悞F"1w=E/l4AIN_LL.61 <+#w ]qg3՜ 1N3Pvh{С{}oS=nnn|S_M}>q4'm֬xƭܿ{߁~ǃu<777xҝ)oFFFzyyE?AܿBqEh[s)_dRA}G˚rE>&(m&1 mlDUb>Α(O.$bf^cͪmNva=L2LLܡ$tٮS^6 ol3Pvh=,qͪUk,z JY}mj paͪu+\;s*+7?)G04i[aݚ%K?=Zץf/;>B0e4SIN?RBc׮^z Eo8s6y03FfjF4K$0kt1gY ZzG06?:8I^DŽ^y_p=IhQgYL(Dgz BAC0wT_U,5( rc4y<==Oa'N@zeaaԵ20#vɇhzCNX_[x")+,m|t=ոז U[v@._oI,l.*$D\ ,u=TEM5͠p\Z+朝0jƲo?R&a`][3APHtu` ?dFpˡwUBcmm-H|3Ő.8!f'gNkq+l / 8++r\<+#we,$10j2\͙3!ِ;D߬3꤃KƧd.Z桥0 ́%qHOO8e4܎J5ᣴ ^4EeU_3:A\솝;s6-xU&ey)Oj̺"vYyQ-j =C@{HɿxZZm#{OBG;Qn͢[PڹB@ hB ^tQ&j_"nُ7P+;g|S̈&Xtssxq.GLg啕nfp|2(v{sj4:$s 929-j; HM۠Lu_o0r-Pk)S.\ W *`d gmebՙ'O_yZ.4bɆ!W&ʆ-Ӄ$1z&Fk^^l68" m .CH0Lt-Lfx=999ٰ.?x"===!cggN?Nzj=t*Ϟ xV\WQ vpկDvygJ4%"K \`8y򤞞ޕ;,+9V %ZK%p 4aXʨ;V+׵ =7Oh"~m+7ns, 5dK .0GWRȥrM­Ԝ!)hHzUIJ.]:(#lәM̄lpK_wXY$<8" $4[ @=0H!nݺGWXb?InŜhHd%Sn[i,s.n:LXm׎U^;w]aZ{10r8f} A_|4WUt>&3giFhy:iԜ "A Lc'̜ ᐼR%x6baxp_~ -ڱs ~yh^yaPF&6A 0@NakSzw1AM3y҉0b $4\0H!;.$RFYaᗿ M-&Y溪jz,>88مzڴfoWI-|ƎשkϿYͬ;ɶOAY4kg=9 e"Q쥪ktթ-M&ʠ|kƢY^;ձ/6x)לt={Uĕ˚_%c#.%eVՖOjl9KaPlU  PFΚlv킂OOOB}} 3zBV-[W-`2 Fae,pPP0cxu >X!j4LҳQ ~,Bb\yP[5i% {Kmu\6( 3y xL->bA=Hh%xAِ[ly6_Ml6;.fߎM46][Z}~f;:d3ORX/VuԨ&}w5fM^*L3:*!o&EdldSwg.۴KCrĻ ~H@ @ @ ~ >{68T}OH`BpEBNW_ޭ|m'Y0 nU##^TY|ncK+wU6gAcMC_ E Zb&wP$FS̕_idT'Gf߾}/^<}sIZ%L(,_ N}GoA e C189fo/zoJ,EEEK*wU䃁s3K.*Hq3 f¡}J%7NO|zz7Qwb~cG} %y4IaR\5su3AЖ` m);+ AW\ Xt­$z{{p(>B\ g~Ӻnȝ3a0\= ?ڣs4mVA24A ~(!-II-ܸs)]6sX}/^ti pڵu5m$ Hf hK0Ih);+ z+d}G{uNzeQh2r'L a,qOfs{a/ {~d4'Eo?yyymusDjݻw7NM6X<"RLx)hcc$j\-?}=Me\'O¢Ev HrA. !`,R`6Ff#{u$ڍt55F4+c& A=pAb9LVB*u@](WIm7ͨ%\%jyzznٲk֬QXW9qĎ^7] meMhqyBݖ6, %Vd­$z{{Iraٷ@(/ hpAjtre΋0\HˁɮTfЩF1Nc,h`(eFy[jE4TYzf gE,(2g;RrYԼ$BR>'--0==ya@H ޖi= @ @ :V-ky ф?ye)|~q6  Tsp :z-sYˢϯ$.* ;8\>}Mf]/ "w 5%lݺU򢹦$'qs+؍#ỎH$lm}sc~(q߶]Na9\wx1gτy1.D <-8Ff[dETֹZՙw%?OyVSQHy4Wm[8uIk9 3i lS)= rț/S022L26:/9SHownW?یP ֗>Fv1zb9 ;|T+׵A c+i0s8@_LL3&@|­ɕgy1wH͙b6GjX*?@B*vLihlX2OZӓW_/&&wOډonK TJ4]Jyxe} $f<]vTc1&}ge&g_|})a,cz"`!S<6R蝘;_iKy Br:Lw}5bof"oLa 10 T&L063ꤘ Rmf <И`lD9/v ncb]k ./?fc?"j 9IIjD=Ŕv"=4 =\\3W'9>?s4V)@Y>ŞAIȱmkJ=+W m[J0+soVI9|ջx<#:س㣢`Izq]5?,2f.쬠>R~~㨗#]' o+5Ƴ70)sw?b ,[ Bve򬦣B yvEjI+T3ئ"݌MT =BYWT-mg CusB#o}_DyK^jJrztjh3},%ٜ޻g8ky˘%D ~h'*xA3@3@tjk-6ĎBWVfWY;s3h[E)#<#:r2 Ja 9&xc~C1@H hiAf=w^=s3hjijjiZ=Ļ ~h=xA3@3@t>H͹iCk9w Bz[gRlD{5|^PjS gAhBs,W59wE}?otY@7QFZ9w Bz[g UF:W9StUh,--5 teL3~W 4xRlPry<ů򾢎}kK ޠ'P[Z]1b #2Ǡ1p*Y6My\yP[l .ߙ 6MJyNT݃?@\f.蒙3Ԝ%.?)P2{ʰ]kb4;Dr!wgDgNRs8ϛ "2J0d <[慺,[&fu!wgě\`߁\`xU=6/e1O;GOօPIoΥ|5guk<֬-l_5e7Ej72=эy5SJ׫9+b"(0H͹jέf.E6h:>s,_{8[ad8aXKSIky xȮ1e w 7Q @c;fЩF1Nc<<,=K3iJ֒\h=Axz7tQbH,E"X( p8h=tkĉ?4"#GwpIHL39m/~N;:" n˩G%\hB ݝn0ccXYIq}TKG @s A#F:: JԢ @t%_vKԢERMAB  @ @ ̅@ '" 5]yE-]3K+nEԕoЕ 44ʋVߓw()+;+߇[[c=xFW^jܬKN:uegt%ZB =4s!1xM .Sݙlgᵫ=$.E0㿘2X@l\|b"{my۶mԿh2a܈(=J^\ |~ u_91Q+L6XR]e2[~ܘ~y h{(UnCp4:z?mm&e;ڕb ˝;JAKa–:&M4iIBel3 V_K ޲{4M u5`sNϟ8Tb/;=.c\Jj; 8RP5⚿JzȖyQXl4;jJHHm(oFFtTe!YycAcYWVq-kӞc\$ąg/lCAݺEԭ[=Vb BA~O ;aْ#eM V.cƬ]Tq4*ib$puW::KX Dͷ_kpGGUw89YdP£k>~k'ϟ{UVri͝Nz iϿeLocp^!}}v૛xxC.&Li, W/pCQ M55mĈkSyqQѬq6EqeTƋ1_'_ﲟ}"vdžMʹ֮0Ӧ@\]+|K+;prtttttɠM-\~Ͳc{ {>uo;ߢ&}ղU++I}?UH˯l Eߦ`7Ϙ0 \@ȯ,}!-$-vX]`n/jES<*#9HH=xq m⟵iw_e%'YHYENjK-$jD|ޥ{LjoN7 EF:yxi)157R*>ޫf.'ѫ$J `aa.w`!Mta,4.\ 37l!C_O-hfg &;=aBʬ9`{DօOB tAJ keꪰ*v,X@T@EIU M*Uҫt$ǰEWQpo9{23sȠu Օ岊**-7ŨIKeyMz "7WWV-]U[>ؘh/h?UUU#}\+\pimJ=oIleL{{{PVOF1gƄG'+kfZRW15v`o&iSYaU=axfcs=:|PZӭx nduF'ao,%&Mkt>r =ZDr 8뭅H[cOo(w|&R_F$o]|=d2k[⟆iEwtWY7RWo$ !@໽͡6\'9F[۳߄(BBʯ!@\4:]Gߐ""q@'@q-fg%h}h{N'BHyRȕ&d”H! !Z$@@ 0#W| O;!Ĺu4zzgs5H`%&%|ě?d2ho䴖pvv;vGcn7}yGT7gNyVt- 2 R;UثpHύrKj`S$P_SOz*ȅQ\} /b:]v.@޾IwrrvvgVU{|.ʽrۘ?[,q.Vy/A.8^IK[[[[[[CEn[^7y}0L69Br*k֮5F)( y之&yQ.nܺs8edtO4Jڿ/8GΘ9"nmbK۷`~D$ -/}%!yv˿@Lx׹oO`= tZbrիaR =5ؠVJ7wm;y_ yʘ>}8 xe񃤾84T=]\-ť.[6q0ub4b>7V]nzx^NSupdS']S3lk~yꇥ@WU:oٳjѾ_`%&y?0c*$ ]*yD<a^TCeQ~v{Eb7L[n}SL4?vn Ev S:y.fѕ9Hjo\VSͮ{DqӞ/^l>&&&66vD%& o۲]8ϐm^4c2ºZ=+ɀ\3RNwADD7ip$=e%W(;g 9` '= J/߰W>&{ ҏ@*+QD.c-s9B1 2EU$PLB'/Dw O+wo$&DR~ ))FdD 8EBHIs(!CDToaVWyM"D!RPNMS!VTՈ_EBH5$rE @\ŒpCi&쳞78 {b][]+1w= V4_>4yd϶g)/@caذlm3җZ3ԔLWbG`ZVISKɤg|h#-N6DI@\s/QUwl :tHc/;\ϣM8|x>UBDjC],,,-EԙL[?o9RbBÞ Rߵn"F!u{Wq?"%liiiii 4I9]|oS9}]oﰿ#MKwцnFE䊍K3iB(uɽ=%( !ܶ Bӄ[FWt (< (GU09ą@&eUǘ':WJ$m KvesX*(l?}UQ)މ(5rd۳ |VYr*D̜|CC!At$Z2D҅/X74In,r\H>xCc>}o?<wKnF{|+}߽Nty?wfNmn{J+2djRDP6mw'flk-qkfFF[6o>ߜ*!Ԙ!X]2y(/G-i֩Vvcd1zqvɬ874)X[ᶜwXeS ss )OtQ*:SB$A%'/aRt+=/_{h sssAL&z`_~؋0 -*z}6*>351vw<lK R?p|r4exҲ+K n{it_^sLo}B-⴬55e~$DKVXcԄ Λ6FU^PUU_!R[S[æJ`lnGk]3(Hx*gExȁpo_=GL9ޱ;P܈XmXH~sشF&}_DK$< g9ogO"_!j*b#'*%$3,"v oLA"nO%|YMqU[ <5zqez(2Ųܸs-VՒA|Yn ,7_l%r{px&CX/minPo^|Q)!rt}C[ @;L imZ4: jUǑ' B{a2a wKT%eW "e }| ]"չQ*j BžDvkJ_V'N{v@01w=oVtA[9ߗL&D[={|rXS x(fp4dw$;Mx>`FE3)@Ln;x$e>?ڔjsQΕkעSR_?JZ#G QxWx]޾|jneHauE.O+ YӓY)W( sɦ'mPC.~ 'z͇XK|]X'A"+_ιXX!>q/ͪNGCw x޸r(+AˮޘO`%>?⁖ܮʍ$f v8w:QVPXj]a.`p_;= Q̨';;ŗmmmmmm El޲iˆ(W\2 =5 0 SDd-[sOūn..^[0Փnvnp!'(cOlOK)j1(irޘ;w}o5x`>YlXx[f*7<#Bn(yާScN+ Ad_ a)Pt"v #bĉh% U,(ѳQx+`ݺվo]A~1>QDx:%G[X$"znݰ:<_1gw Ԇ-xm'ܪ'6>Տ6QQs.>f,ͳЯ,ד MP!!'؞{cWSTGE;2E F+h:-]=s={S3ipg-,1y^hM䷍F=U۸w0bC ҨbbRckφmЏgp>~v~p__Dq:.!J竞3/10db`KGCse+RmמazD~o9]G_2W"$z|b ;k"_p=-_ bՕe}hyIdկU&͛2' ?JE9}I Q߭?=I@'#٘ T"@BiQCDTo(VW|'\?4ԽSo| JQߟרF|~wrssr*LAp_'NٷC:Z6#W^N٤6x1 | ^Z-g<0`UBRRumlA?qC=}^sԙOj{v@~ظgvoG yEK)=!Ey^נ'D{LmE&pꢓS#ۊIƵus&ſSs:8DJXO̹ u%zNTn9|04Y7c/^o?P{/p8ѱNr\q(l5!bw4 7N\+pZ'9/++?n)#"8w͞`لwi.N>] }]ڷ9d-+85+8iz?m(JQ(ݻvH양prPcL#X-'-8mQH$ti<m1[ދ֪X%TP(B0Ahp(񪓮!&=5SPͱ:s؆$"1BssЭNjOysQ#m{e#祧a;4"I^r%HZVxيcǎUWQA:-e6{ͻrD{vPr|!x m{ {,1 [65:z5[ѱJ Fqq.z˦nYO_o4_ lmmKwluaC* ( V5,AJLxP94ܦ-/ru:[VQ9oVرJaPw9z#"${o# qv܎ ѳqƏK{<ąd*+m"FJΡ= coX0]Ocmy>>HmL%13v@ʩ߽5]tq|}_WϹ\VU5sF@{v! NWNq$1#6imnA$D4~ * pY+2djRDP6mw'f8;DQ5~:h?_&H̜u!2 !z3XUӾwS-]gD]~EHaFߥi.JH/by7؊)?O; fbT[m>{G%#&w&:T&f~.Ku FlPRjQLDh KCmMM»*!ˈK/*H`hϚזiw5I+tؗ *[:пhXa6:Zxx|CjWyE1:dr }|n|Z_ήovUi=&Q%qZzAUuIv_Ejeee,*)y\hT{v'R&)+C%n)MDxVFxu⴬55ey|fZ&lXv޴1􂪪V?7"V)kx?h)ɮ\b | B>f6'e^QIHdtҪ7,:/unwU5)UB8V!$m1~0j?c|/qScee%}u//hXkP"^dp=) !ٳ}*8Fh(+))++Iњ=š'̘4h:d5mq4TFpmP_ 47P|0>%~`ve[kxf6fԘdeum XaU=a$7m^bf勅i6PKEEM5-mDzuY5eh=(x ?TgM^_gpM;]W[s8*N]DRWEm%ҤhC%$+DZK^b2V*J[otfFZqI D*))E | QGbTfZRW15v@c#B츰K 86>3%MSPPozV?c~^o9ԘLfK%z/! %sE |ɩ4# rwsk4[%M7":tAJR| W`C>{=|7Qd7mǵvzB;>~ O~=0 @໅px&CX#6OEgܠ޷o#3@oD"@"r @@Wttttp :@@RZ`aJRB |,, -' N\- @?B#>5cXMV3zkeUIݠ^'LW̄X^[)'3_* }Q؁OK"o7|->gdzgdg^c$G"r}>|Fϟ=(AJ~Iv9\|qUegdzzy]=~5wȧOwOS ). X=޸ulem:~ܙi,&4V=| Ii!J胨sh5qVtDȃlA&O/oo_An@p~i 2ŧvPU9v;@ZzFRnpXo,0BG2q d [9GPd>yX m+6;BG;"=v$>x4sHm:#tt:.LPd$'[I$o(!w|?Ogj);ux`"Db_ᙐ/=X03WV{H{kB9ŋYΜ={ƓU޴_bO/uFyjQCFц6J LOS֙n~d `Xh㮒2l\-ruܶT$b44:򋂃CDD >? Ǎ{iWhK GD˺Ӿt2b UeeY`jhHdNeKVrܣLMeF!Nn90DhT(JRTAzCM[y`eͶBPaH(8u]['ADNSuy d [9 Oo_;3Ƿ^𮩍D:SʋҳBƒ_?$8'c1S'f_'o]n.W ($3uR7'='-vvsc] N-Yq; 环Ɵ$O/+jIo{9gNJK'߂'|2lϹ,7w5Uzo~%~t*J sa [W̊E{[K{[ }NG`ѭ-9yNd%4|u! *k|C4?g]UZ[^ =C!bdjM+-IENDB`bless-0.6.3/doc/user/C/figures/bless_number_base.png000066400000000000000000000274131374060072200223710ustar00rootroot00000000000000PNG  IHDRu0Y pHYs  tIME ӅtEXtCommentCreated with The GIMPd%n IDATxy\Gǟ@¥ ūHQ<[ֶw[/D*"*A<E"*ZmY[[Q뭈DHvg?1@aE;_?>3oMv Os*A YDLP(P0+t,V8}ꃧs?H Bj("==Lx˨&r}O LڠIwb ioԔϺZU|ZjKR ܅9{6'rnA kdV6 8CqA3wHi)[_z1|X=UW,zZGeWƼ↿OH!_,٭6_=|,ھyN{Bu*Kڪs$0F.]G!-LX1L/.]`@]+:71KY-^=sZin(سzQaCmu]o~k)L w0A6IV-25zV[s+SuS*ˤ0Mt̔)46( T Yjq!ӭ¼^<r>aYER5m"tWV}n==`tPxV#8Yȅ#"n'T{f>ݳ)dۡ,ƀbXƅC9#s#ȼiQӗ Fq{BgN1ƭ&>zRh"J~qh󅪊E3Y%z?c@1 |qŸ;a r˻좴{grMX}υ;']2oza`][}fqV6͚j\q4\bEY;]}O+Œo\>Sؽc &icp 76}hucƏ='$"]MrM˨.:Ն-eKק~N^®*[I[\4e7Za]6˯&)h!!yWGUaeۓl!dKYzzhWQ&M[ W:]de*.֍/%o=ӌAub=6a1 lr=xymmU9uom3DRUQbL}F뿪c{%NZ1 edmL} 砡#$p1q۳Fۘ yyWS5n*m>c?tW7[)tC޷U80Ĕ[0ge)ztn"ubr}K"H޺yuPFBÎh]);4ٗl<)m娥'{^|JVҖa^!Zr2?Rٓ?HƲ2Ss2Fy2𐘸 ۷oKMdya?3Že^Mtպw ;[׉ at_)Kz^إq*gCV'@cAQȈX9Zp{={:`)V i/+'|ư>^46G̶Mߑ".scՌAE` x9bvu/ڨۊۍ iV}g_PW&!]̼gTG M8~.@ϗfm}\Σ̌{ؿĿp{T}ZI[k ~>g]̷=W|Wc,fbܰIˑͿr]w)H|<֍>uy%n|o" "cDڒW>ZqԲ8<+c[Y;m4,GhF)m|c'xS5P U܋9p÷Çٕ.jy`H'DZeVRǤx X#ssSKó_2͸5jԀ9U3gk+vRyeJC;E'i|bHQvHqΉ]xWٯ͘ p@5I#&vK NL[fƒ}C7䅒kl>|I73<ԟxخ:J2ks/_i1o~Jq^즄yYOfVN]KGwC|I-v&Yeq_LNQA.͗^kb8fAm0dKHYIoW\ZEoUפ&f+ض%2 ,Hjޤ'_ Xrg'IQKW)$&{_>6&xxؒZc_kc3Q`lfեwJ2t $>1bOJY:w"۸vt99:X6]ס<8=BbbխKվ~UJϺn Z|?΃؆;#V.BΨ%c viy=&0o [.꭪EF䟓M[w#U}NR#Se%\`<-zP(3<lL jֻM\38ZV' \A;!,P!W*] 5  Zg1's=GMAy1=3ж?M?+3C6̰z뀗.? AH5[߬BZ4*zh 7=\ꪼ_VFsH_1 He&CR)P( }f,\taα+B^# GP(Oy^вu[o &-LB1 BHOw.]"@TJ 0C( BJYs*Ɩs*NY,c@BTJBx=¥A4P(B y^n9C 8!O/KP(Bp9] H[B77|) U@ B HP(T) * BPP( BBPR( U@ B HP(T) * B_?PH1 MBYX!F"a1f1~Z8* E SqD" 0FrS(y/ È XT)ʛ} Xx>Œܴ(6&t'$Uج)޾z-oX}_r9?`g7l}0rՖ#]W(!}griًܹ+ݙA׹a$f[Fj7 ;-eku5Vgs_.FfolހúY8d7JIF[D51䓷e)}t27P/ꁘ[O먬ʇh Fva6߾oK܉sTҦuQS>jU{ߨAj11FB 0 "_D2aaf2EޣGӃX(v A+wyD,fx^e36=6V5u!!D[FzP෦b[ȰYAnͭL<}afoร U :6ê7_8.$z1SՋO_G=,uU; {9=RF.u{8#]Y=U|{TiޱuwL Qyoy_}PwXb ({qȼiQm 0*x#ƸBBgN+\a^9GOYv:yޟ73bcrݓof]B3j#0t+5ex: /-M>_یA`bѴXmhሶ :u/U]Ο8$e"7 kRF,F"F7sYyrvg}dk,YeS?}Joׅ4\R@aFjzVMcn/y޼eyOb3Z8~0gt񪔯_t eIwҬE O#wPY)`ڥ ߮`  [sjm^ݷ3YIG #7n$EM~GU-,7O%, i/ջ4)~v(v<+wk_R:ʇ׹*ۣ]T{whBmF^ "ܭe[BW_ݺϓx2;iیmv5Th@mQicZ-oQ^ V /Y$S砡#$p1q۳Fۘ yyWS5n*m> c׳sLLs|\\e߹5;n^ԻѽаcZtn"ubUL܆۷l^2VӼeWL [~9ji޳$xҳeشWDf֭̏v|}4bT_H-b?RW>;1̦c8rW#z3uyC{1CoJIޑݧkjkscS{a |FOg@ űgIX9Rxhf95ķJH{Yi _|1lOs^46G̶Mߑ".s$͌AE` x9b .oƆSB^̛}=ožin͝4jHԬ̓fW'[8▝t(p _ h%c%t13xnb\T Lsԅ-H:mRnPb{ cyLO?5֭UUNjV@eS[˦ust |i~J/qN,2D Qy>lilۊ)mD- Kz QٷKW.4b9~n~o5|mQW=gi%{֤@P=:!hON4LGπ5277ET;<}!#O܌[M Y<_z1sbx+%JWܘn;ꈦ8D. ++-5(;"/3mmTA^K8\:NQ]"R~] P}g\/afx?)@]kutehu[r!'*;Ȅ>6qqrx&>4 ,+^)=J{^ mܵL%/?L_e6k/P?v[Y N{פ=&m466wҨE{%EǪ?Xcސr & ZXt{ =--O [8.؋ݔ6/Ik(n:5 롶b[8.) 9? `R%qxadq&f+ض%2 ,Hjޤ'_ |Fel$G]_pU&Άl}Xu>Z j)k|}}l? ͬ#IdI|bϟȕ;t^ID&/qܩr0rtlr* CZ8Bx[mj77wPuka8j^|铤+ν/A\1;\e~2&إe. )M`jqj(Po@mQDO~gEpPfl`( 0SQ5.N0=(*<lL j2A \CVoj-O9јMA3j|"__Q0'$pp~I[3Y4xv@*e% fğѾP(o EQ8 V{U GP(7Sy^D{D < 4P(ol %&΀) / |;DP(z8ĤP(Y0m BBPR( U@ B HP(T) * BPP( BBPR( U@ B HP(T) @J=.3B?aV"D c0?*Zn,uIDAT@с V(BBxw1 03|=7 B'#;Deg?ƘL鋃QBPj&Bk9C YԺM[!f%afBNxRtg]e#!zĪez f;RqLHK٪#]Uv(!|ΞG[Pղ{&fc[>u˨FB\wJ6ճgt7}B bn+rߖ3M~|ժ}W_Vܟ8&5a@7 "%7\bȄӛyNMb&,2s i~>*yBB!n=rz\8)"p8/U~ {ʴsf;Z . *[iLanwW_h7_8.$z1SՋO_G=,uiT_nsBхﷆ߹iV]Yc\4-t{zUˤ0絸sfJ@Дuﻚ57<ȯ /eWP}e/n7;j F}7BH̩VWEl:xS֨]N~^>#~rв3&77`FqxQ{RSYṂ|?;, n /`nz6vzoׅ4\CmZU5I,~io3E y}]KCSԪ}.OV⛄N\)#xa$v}8'7il7~G9ux/O;;sܖY ͶE 3Rӳm }Z>|؟$9੪sNj*OJ:A*E ^9Pݚ>ǂSf0TVO0ғm* ]ڲKwMXy޿kxkwmC73NXqvcscm5M54)~sUf0@`d휦y7nQh{P%+yZ~ظc>' .ˣ1]U v:cKi>-s]O w9c`FwۙTKÙ#Αf7g&#Uaeқlh*oxe3?ӣsG6Nէ+#nu#u'=+2MwF-tf5l Z:%$x~ݭ{xc:mLE_5{%NZ1edmL}砡#$p1q۳Fۘ yyWS5nׁW>;1r}K"H޺yuPFBÎi;6@B.M$g6Ñ˼mؾ}[j%3l? AwtVZ2)m娥'{^|JӖa^!Zr2?Rٓ?HƲ2S!s2Fy2>bGd#fvO=[Vٕ:aۿ+lOJIޑݧkj5Թb?pʽ k>Չ z|P@mݭqX9RxhWSckora SVKcsl.B<'M"ckK1yϼmq;U 3v,W3?vuR@3K3ҰIˑՑ*V#p923vbqS>m)Im.=$F\] V V3:@ŝW%&ZR]Z7DOahx$szV1-y#s)>žLâ8P8E례#n9|'|]9'8lOYt(p _ h%c%t13x3χ-m6߷۲DgSC9a֥7v _0暗xm4SsƽmDNy9lër4B=]Uz,ub-Z6ԭ˷nLէe5 =MVR|s2f@Utj=L2F>S}Օun[-]>?EظU QޠAow;{5NuƱ_XP)u>MMؚG7)9IcoIZ"O!1ܫ4|,31.-vY8NiS;P ں[>IV'ˌLƦR+1?f'O`J}0cGA c.I\38ԺnBO,_Ftx9=99ca6'wNXu%p&)acb$B"!l}r~{ 2j|"__~\'$pp~I[3Y4^KSɌdƦR#=$BPj; &MOEQPf u})yEk]޷^DX"XAIAqrg@;4cB!D cw{@Pf`,,u:ȡܟ9+ ,WB= AOvnTog˫eI7shv}4URhlR'/lK0q~a3}225i=s'Xsν~>ݸ}_*`uE+ne?D/g 5׍f!h:a6vKjV_b闻<)/r /3RP΢,B<QOE|JQH<]}ϡ-cݱmOQiN/*zЄNPs}Y<&e (]/ߖ@8d܂iV&%W=5 vL 8?{~3,6 Ƿ+쏀-tԛ/6k5Ǭ pT.!xny1HI!K!=Ј7ӫZD!=BzKK8t#p-V%1IIwۿ/ϴ}t/^_>Ӊ[iUFN ( @jh.͌ |0=HI2\G||r <=]ywD*"Y3ے|%m^LF{{=Y2Nͥi)Mxf w2L[{JVmT=VۓK^[ޫd6d\ ,ކ`_4 B H<$nw+&: |I(Nf:Pa\yt팤UkTE֣Qhw}~BB\i*d  |B'=1/^K@7q9c?hVho゙%W7,_C l`%܏LZ2>xyP]3(,LH_D[QROrDK*S#d@mt Ǟ= 7=.Ô;> kX9K4qP9嫴֣d0_M&(G_mGMxv$o[65 DS1ұnyz= a鉔ibOӺ H^_&O5{)\!*gY;\h*='lwWvEWo-Zm{m%wLlW w։i9>iXkz; wac%%%^ޟ.!,EϪK\ [5u?~rkhޘ[T={qaMt8 E+IG| ew)֜ìGo 32s,;t3\8S?)X}:S8sGX+=[2a\_.h6O<k8p2NdN]Lil:PP$22f|,gE7ff| o!y* JUb*CRL\-?1AR{}ufiXAëe+1һpuӎl=uyWj4)th#c<[%:MOc[8³ ׭b򷑙y{w#f C1Ņ>ӥq.݄џ@me|Ȕ12BX3ޜ'ɸyVxd \~x"uE쯰-= i^񳿙0>ia.,5 i絮)shg-gIoF28?86>e炯[ΛTFK"i^U?N;ȍعk{#+~nS[4s!4[[׈$k^yB&N[o'1Zn<ʫ_okz )~[yY=w~P{R4tQUL;vm˦rMi0c &ssZچz2yP9Srq1e(eXyV%wI`C[KЏμ1]ęC1['L1a0솛C^MPt uUgd} c[KHnՓ:]1ͲcTm#m=Ghw܇ϺomJ6A vP؃}L^6Wד+fafzW/z_6LbP\+3d86"X_rPN[W}\XԬ>EGjNȂ0B@_N\~Թ IG~Rsv˕SbשH:6>2n-6t2yUcvѭJ[3b=]qb{hƌ 6_buQ#5?Fc:K-Պb|E(3X,bb`Z0 ;wfx,Yk=9o岥<ש4sk78|(iMSQt-9*wr*9Y#oo\?k92O+`Y٣ =9ycJk@}5"\ d_K Jk*;_`s>s~\l͈̃,qňwnQW!RJ󘷥,8>o:3`0d(yՊb|(X,FKC-~Ϗcmf^EQ_m>cޖw$ 1̘f 4@j͜,̑+ #dͷfX(@Jj*2 h5gلxG3ϕ_n xsr|t(s:-6q&} 5*$aDέ=[cbD~ǵ-ΞzޕW*?;oǍeȢ|'Ah4ad8 7djTr$`1;C\ܭW `&۽b"90_eP3*8FtǚZμ*`XPm)w۠¾ʑ#a  f  &VРBhӢ88[hDreh4GD#N,Z9Z9*IT75Ykѻ6&kf4O2G*,muY'N:sHĝ.;[!e20dHeJW._G꣄T)OT"B j;5!!57h/vv*Gժ].E SP!!=rD,hո{xP#^^8:9J@ "* z=fED{*;4Z絝!DIFѢ8 B!B!$ B! Ν;B= hѢEVۓAB2 ޽S BQ<ƍ/(HN7ͩ*M/k[6oBQA?(p eH"#pZ1|BG# ( kNu5 *.Th1u!@}XnZ9 |v.Dej/G29/OBycR}f̹883O]pd\hK;l=,s'D<}9-h, ޖ98mCѦ{ɔROyך_ythPX,X,2*x# RLv8h'x c ~,Y 3XHZ G$M_ɡC c)c>aX Vkf(4A/?C纁xyD+/=JRv hS^/@7li%܏LZ2>xyP]3(r5 y&/[(X9%}|B_q2Ux=yԏ={䃗wuGmi(lz9BJ_?O%e])SAy|}B?i*4gCiZ/o6#(6= #>~wwaݵ[\˵utѝ Qۏ|\xޱ=S/ "xk?6k컠6,c<`@[A~ 69қ`\h0yc\gTl*;PU}ǰO=*>A82xR3-sW#tai{qaMt8 EoI;xe&<_(_{!mĪ&9dzJ%o};3#gU%YB{ڳ*71u>lJ#C3{։|[;ɷYw9Dl{;/pJEȥq, Pכgᚳo5rv".?l?kB&,:|#z.$~5O*x?^tr$osW0]$~V@)U/miT.T>M\"22s70]ݍECQk&.Gg |!N -AӲ.8Wۣس]ܞalQ /5 ڿ1'~tRM2X[a2]̽< i'XÅCyM=rH?hYSަU㍙/S!dp<[߹&" N48{`( nj _{˚̎R $.s ښw FFN ye`f˾mÂHWzTVy[-(*̑"'uIAW} [d~[3s."}&ET }̀)wMD 9"İ}W@KO;0 "͋j~7Ss'-ETo5<ϖW{6sM( =>ղ;hXSvWC <m;/Us ~NB}o6컠66%6 x(' r~w{/'EK\θcATK Ƴ`>ڼ9a5OT@I2!L?xؘ)GpÌ+p"C̉Ox˚o8k 3NA#5~=9#:=gH˒ 8}W킏6B}:fOu%Sl5Sl]=׿_m{TC#鞾W|ZA q:k_Y0y) dRRۼD }~mw](6@9RoY3ÚTҕxz b8ԡ1|޳&4t?|YiLȂ0B@_N\~)[ȹ>!||(JMvu5H5c2޽l1$4I~],}03Cq̐ԋ`}i5CR#;m]mqaQrxBQxwcNcS)܇.!wӆZ6C~mpY@}ؒǦwSc c/[EjaˢΚRzZ~9(raSG*.6f-5>TINJbɗ3坙88:nSyglF\eϲ6U($F*3kB@Bn?䬩j \~ INڠhxy1/.6FHH@ N:'ZlMl@Q0>MFVqߌ<"mPD鋿|N/rae $ B!B!$ B!B!@!!B!BH@ B B!B!$ B!B!@!!B!BH@ B B!B!$ %m^ޝٖ$!tq˻ _\4ݲt Z\.B G$+YT9}5l!.v ݤքBQӯ;fssw&vgBv?ޥw*y]FI. Ze65㕥GIJ !!Rf^-:BƑEZq^Цi0c{\|M3wAڍ_E"J8&5/2TAPe~S}5-ݻkx^DTІt;=j*5YX(V9wJ5TBHx訽h=a28<ń7VXk;?qMfyBG^- 3)TzB CKPmZ;b3z3HLrr{gV؝g? zS RB!x[֗.éb62~l60PiZ5  p aаZq&~ިt q'8{.{SʅBQ2<+/8T+ HށM='{ȶ}y}:(מ:>!xbc([jJB!=B!@!!B!BH@ B B!B!$ B!B!xx !blHeOBC.ٗL wd2a$$$Hw7wVFj!b!&:ÇѢE +TDVKňbpܵ FMrؕc^! ǏeTPQ*DxjJOTEѲI\"* S)Wԅx)[ L[F!BՊZF!wϟ4lJUtKŊXKlIB!$ B!B!@=+qf |:->KFEz%,$C;z9sҕ@[ϳzw8-w{(Bb jԨ+2$ w\}9TzO\ƞ(d\k臶8Xkl=Hppwʻ[}G29r$jbȑdE|}d  \WOߧ1o\ɾ4 RLv8hTR%]Y^}[<:(rJ&NΝ;Wcǎ_z 'ja̟+ُÔ;> k7~IC ;-J޵.e}z)lf[~H;痿D)kB^zxw7aѩBsf -탾ދucFL =^>i0/RPra刖T˧ -F|TŶբjG$eՁ+[L%Z-Z Xt"d\b6Trբz}&XsÛougfZ캱ZS d0Xl?3^z,[ ܫ?o:c^d\XS>w3y'k{_Ec|}>-g ܄k8 {x/^-'[i9>)އ9=Xw2W-Qׄ<\ZI']oUy\8ɦye3wJ/fF>ϪK\ [5u?(,!|e?&^bKW=h!=Lzu#e':%}dzsxzFkɗ'II.˗rgڰT2&oiьocML;.\q'GGGvM:un_NvލBD[nh-@zh2M˺^o"`Nu!ջV2E%h\h(*Őv5u ;P't 7 spa{i芽/ 2cqyU!3kw0tpBuYyo8aKmic!W\0Wy+46Q98j$Fu3wi c ~:8xkxJZ:PQNbBC eJDϹpV437JI䵵ؿ>K~"\'[#/+{ߧڍ9~:Ѻv<ň|4/ܖ0ېǻng60M4*VFFLX\v2a0gH˒ ro&6th?]uzIa6`>rpl̗},~k ɭzR]gCmibT(▼c^. {ODfdͷ* Sl_<c*׎ne7ٙOv.rrZf2ɋuppѹsg>(:tΝ;ppp >Fn|;#ԜaLk_G< C)Po;;WfȂqlE4嚿šZ}WZ ¢f-υӾfB5t .+ܛj{Jk䷙ˢޗX;3Wl]Aqq;uxI4 Vϫ4ǟ煏gP(ԜcJ xPϗ5O]|vͰ.,h䏻{~Ly}amێMѮ]{ON>}7bcn[.X| OTIDAT\Txd32ذ~C^h ǏҰQRR]믿f̘ӧM~|uꄻGYo2P(^>.J*xԏ޽{JPPH.T+'QH*TX!= !@H@ $ B֪XR!?N@Ql*V%ZOTVOpYVjBJW._GC<6b)U侾G!vjBBj=oo_TR1IJZbc9x`?A!SP!!=rD,rV XÃ!5ѩDBT*4Zۻ(|^t {B’@^GDD("* :(r;: 21s\\P@pB!Kު$,$I'y>NW=]_U ă͎"<mۥR@ HSA(U@Yc\JMAߌQ~$^dL PPp89f?rA B`y>x'z ^FfEdg3pSj#ztw k}x+G4uT8WT ]3JzI$>!>cg<:\ncpis(foEF6'$ҶMV2#9u" 0Ňw@;q!O;^9<|iC']&屫ΡmB" )>9/p#tPdòxĆ3"Գ.gq̚yft'`yCѫu"g3RXTC5ק'P^'VmO^FL$< ߰aC?@2>]qSN7qowRٽ;Vtem'y_?I!̜K)d&nf{|_z53,#yh^-d ϫ9ɶ:m-a@лwZ*|8ePW9e߮a]IY%ً)OOdPZKI{ ={ƭ H=Zלl/ΤADr?n1(ĢZp̉OIę|X>Ӎ{Iae_ ^]5I;2{'qӻl-=26bϿL_;a];&rŦцI\ڳt₴iZ:ٶe2YM"il66 21M{l6[mC]CBvAmY[7 319PqtD:lp(R0Tvpݪ k) UU%w'dEomiUywSMg偺2N}s7&+'ͅq'?-@U3kkO I>ViER0  5jT8Q~O@FޘGJ:r֚lgDlف̿w+mq֓ϖ*}{#Ӧl~bǯ_ڍVQa.bh%5YTKnx|q󧿤:.,z^%8xh8"ټ|j:9ONv4,:Eel-e 'Kn`֌HJJR %^3]Aiam^3gp7- S_98<%/^@O@F9؇򛹷қ 88d=<!VoNDdQ;ެ5,zd:_:֕_&,3ub])Ly?ihϖ=~ѿ{:~|2=-Ht%lShmFH0 {0 ^?i]k`A '+.Y9wé4=ˠz):euTnΊv4@Pdv AVY( ϏaZXVUJ~ 8T\BL ׇټ.U ͪdP?uط}њvKSՆx""xsPTCM ~?aߞ7 00 (,,sz8>ͪU58d (ˊ0p8GVϘpp1_נ$5 ~@L8\.0#򕄻#HMm͡|46ri:?ҺZj ;+ŗWKСC<!׬JҨ]n8GtL4:qٛix\۫=W3y窝לvVU`d &ImƥÆwg Pip8Hn̥Æޑyn>}!o@V *HcNuVft8[iݎi~6L) 1, ׇScHوaΝ$&&GtCT x"+{NHA,b=}#!1 nWlyrYn-9V)G+HeY ;~ρ1x :&3Lrr -Z6'dT293X Ezz:mڴ!4'fv޴o!P@DDC e "" NcB>:-""R_T2h`*H(P d "" M%44 J"" T2*HCS d "" M% BJ""T2*HCSɠd ""@%44 DDDD@DDDDDDD@DDDDDDD@DDDDDDum"IENDB`bless-0.6.3/doc/user/C/figures/bless_preferences_session.png000066400000000000000000000310351374060072200241460ustar00rootroot00000000000000PNG  IHDRSsRGBbKGD pHYs  tIME9,*n IDATxyXT7 # vE@ME3Z MKhj+*rIsmZf$f(Ȧ  fL?9||IfF!B*H!B!BH B B!B!$@B!B!sh(-! O'3B!A! !B!BHg '3\i ! !B?Fqwp|=]Qը[wo˼OB}Ly \v_:ĺ^$]ϙ<! Y]c0zn 7g[6/]Zݞ7cviٶp=IZ})l)ƎOFHxn)WbŨlȳsgXP~u^s+gzgIix҃1lf<{)fmLFťB0B! fJX咔E@t7Oe׀6Qx_r*dgZR-%u=޴9ͫ6C ?gNC[\AB!]d˼G̀̚_2M E5A71^YVމbN<&iG?"b0iWPm̈́LF[R./zqE љqÊZB+ W`Neס5AamMIv|B!wye=73m`'ڶv˟[~jnYgpܙaI~uG`h45b\°n88pό-?Uy#RVFڶ?k!*\'\M8wz#Cs"cU88V8>nU8Ԕ>66>A++z*c鍐C M~QH3Iy9G>>| ROFoy+!cY6H<ߨZ*/}@҅L cLn4?qp:i8y^{'kۙ4;rG~%ry.u8EȜ >BdҧDw듥7rlPE+'Ɠ9{ j0N^m0 +;k+df0:t2kJN #S ğm׮]@DD{̚5q2)#6L[5%Jf^.v Sl .|Ala{•L Ū4;r)XdN 1(v4csAԃD]hGYSg#g*Ty?> &M}j9:ǓVҭSׄgS} էȱu-C]j0& +|')5xMI}ӫO[RqXӸi(cS Ľ ))@ APr@ERRtBUL^t,uɔ4rK-vpc gOUq?U|eSǎ*Ȕ䔀x^t=»KRǽ^at[zeOn{ǯC'{0m}5Rֵ u-.U4ͼGJ4N^}ڒ:ÚMCBH lƍ#,,d|||bԨQ5^&fh$&Osэd(43 ~dٌ(p&.t/Gw{fqIl㵩1(26dZ/c\iՅ3H|Z6mlڒ^%v/ IczS̛(,\s)'ljMJ۞_ k>cֵI ܱ qXӸ)}\) *5nJ/FLՠI=y).!,;e4IlJd^yNiФfӂ5O+W(ºa-;oՅËY?]\EQqQ_0Yٌ(edu]-'I-*&?)sWs78f͡hJJk~оcغX]{ԗzڠ2$&^a1H ㆌO!$@r $sԵ9=CPveX6<GU Ú1 B;k 'f>ۿ^ǚrsr/ EaY_ZZNNNw[Ѱ|b,[ANvXx)] 3t_?/[Ng(333||TzGU23ҥBW`bA xni%Bܽ Bn8Y֋ FVӾ6T>?QFطNpw1~y[Q̐wdfjjF!';n4YL B6D6L^> ogeI(7e%3!^ LhbGWӲh:&MFIfQZ @IItt\œ d\pJf.8$%?Z(Bcmmn%4ΒbC]4mF+Z|Xn/\f2ΕnĐTT:_!+/*bI c{1/:H<-Ə+mY#5xsJfؼh+G)+ !X%gBdz+m<m :cCE;G}֎v޳s4)y ]l1{#K,!VRkB B!$@B!B!A! !B!B

ss1&f;HGQAA9yP( [O!@r靁 OpXk/Jt+#{;]H}5jb ?u/*))1(,-)))[?eg#CFSk?܋QyMP_ !ggsYd^[߯3X^~a6/~κoQYb\°n88pό-?SZ=R:{g.)ɱ5#R;}_|,]*5~-J˦s"cU88ݷ_d́WpPud+96^:6*זG]ZP~!u x=̡o ꋛ uF9͊9ڶ?k!*\'\~]`>eiNy#}hM k`[+ !wa<]83nH^z /=XoLir7,pXR$RjmMM{wF=DCTO2 w=!t)QUgZ?{!#0_AӚFs^ !2 {Ƙ3y-z\8YogȲ +;k+df$.ф&?Ψk$F^|cן HO;HL]MEC䆱 ǯ?}5rgvX>.VXfzr(bA3I?WM=xnK85(#6L[5%JfpyzJO愾@'Eهy'?fx)fyv =J׿%?뇙6V6XX;)Nkhajddߘb&-ac !nS̩ӹ$)&1UfjbFN*mk]=Rn~.&ضgHg;Z+M@[ ZD63kF #p qŀ?KJHKE9skF<֜8-mmPCq^>?Mlozu+n0[l=Q*{t۫ eX2UZ c%mvAr-p|S$.)~j8!G)tY$80Jz N NU1of[*zQJ~-\ iUI; v"Lmq3rĴTK)T-:l}iCcmbgXcc>}eB?iA%>߇ &5N-oZHxe'uv< ^TAGɍNdgWXw4֨V&\c//_̂.v&}~OLݎ&2[߳ {#HJX9~Kbk |rؤξIɯ/cxkx6tEsX2[ 0M.~GY2?krfh$JzE7.TWqLc}O~?lvA{8Djz:ޣM82kjFQC.%Ҫ NCmbzzy2S ֳӟn?l͈MiiQ.j=gq]ohYYR7AaemA!3IVnx9y>DM)ZM!?Ml KѕH&CaI3ӻ6tFF `W)gެ9t1MI)tUWdof(8]WXh 4hΰyJ ~λ|R͙9[Us`FNjФdKY-zQhNMR[Wyyl]lZaSJ/FA6ΤER۷Y 61tlFJQ[ EwqE4x2(A]^ڋ[֖<T M;t9_Qyz/Wx ,\8i s6W33 WA5_etc46WBL23kpu[rD~-ǝ'\[4YK'hg_]6=eϩ/Wt 9]iSG3C)$Vݷ"0F=5@rsr/ Eaiip"d ru+^ɣYj7Ƅxf=qsk5V|2+-t1?L}i!gLÞcԚn$FrknE|lqT lʿ 9҄]sMRW(RH-֣7o{߻#H||XlX033Ƿ[UFHO(/$1šk#ټpvQ!.-X~]@iI'nQRv&g\4N'2*d-)l-b]~>g~LZmU&*jd":aI Y,b-ldbA xni?Rz2L"Zkzbۗxc#-#yhI f?$ ^AEGB ~ H ! TS*B!BurA!AH!7DB!ă`733BH!B!BH B? @8zB! pp= ϕB!#:3 l!L !7@Ư4]vb0V:!EE撛SW^n.:nC m7C92>/ԿAL럈N`m)i̘ѽH;VĉF555),uČs kv!7P=H}`ԍы0PAyxqjm`v,^up=ԩl})l)բt\?ۗlt~' z'`ihakޮ5wb:vz%;pjE_bGtnb"O5T. a̙ 085<,[٣{2O_?◼vȞ8 W/Gs ޙ@iV C\JWyr$%%%(%$$OpBFFRRRb<~쾒NfF)Σ| =oQ* LMy_yvv#l|VobۅɛdOcL3`V- #sk$''w#o]3H81p^<ú3nx1ˑ˷(*. 5 ޜ9 ] Ӫ ;M+[i4igؼh Nge#iՙO]b>E7/X9OZTL~RgCr3oҋQ|0#'S5hROqfrGl61ؠ2$&晽ƪ6sPy'Y.,I6/AnAªUݻ7[nQ ?~YҀlF 7n &%m4Ox%+N#uv/M婤G~Vz~Ìe|b3O%`ў^ŁtRuy}d mӍ}yè[wA<ϼok[|Cx'-/Fk#y,_fʴ6lx5HuB`^-v{ǿF-J9Uf55ߞAϦ_qO'7'OPOKK}4/[̒e+ΖO׃DV3s̞7iJËҡAeƂ>} B!/X)0pCz=EEr!_ #-!&ABn*33ҥA@Oi!BH B B!B!$@B!B!A! !B!BH B B!Oi%7'N\t:(9nrBX0 h|'N8nt_SSSz10Bi?m3$NC!zNa(5А`x!Cs Z?Z ^6Hם]H;H%]!Q%%% <,\OFc%B&%F+m- lFM||<3,?m$jm"?KW G7z_ʫ ]3-ppT";fJ#f~XVG]`>eyNR_CdLwc)f_> 7K W=kQxdׇq=XU,)IʚY[܍4vGeCdI22-1!g(k:l8DzZl<٫cʼneu|Q H=y"'h_}R'/]Q=Y}4([U 鐱L $]onbnLDhBag5vLrF/>E^]cY8tpbI61~boi 0lNnpU闪KNGWmpC!$@]vObb"ݻ3k֬zN=T\9Ѣ7ojFt,bA3I?WM=xnK8Zwa3fUٞW¦׺=i»&;Âqʥ7æ` uSɜᤨCkX'G%~bW)t<ㅲa3?l2>lrwRR#dZy.>X5' ;bôU3qQo^.4<=l +1uLܭʷk'e&w )~B P6B#zhrGc!򐢨$ APr'ԏ`[LգBEg3&qI1lSVu>TѲi&sKhaw{%ZJBNx8[nc)nꐧ=nk`u(WG-w=o63=oǰnv}e.-/ RfK'\eeTjU5<[$7gSvrꈳe17tC)Cۛ7pɗHZ!A2^3n\ٽ psskx&ص̼ Wxb\"mZu?jk}}sO@FlN^X2[ 0[&ޛT Is~ N#DM>Z߬VnUloF+e&1UݸHRM3:<[YR*LTmpݝ`bz} WA²_NsS!#z aa]AAAp^<ú3nx1ˑ˷(*. 5 ޜ9 Lܪ ;M+[i4igؼh Nge#iL߁%\76<3B(s}C{vOiGLՠI=yQz1?q&,Zϕ:2ݍ`jaͦ[NdQ4=_g^4Z zۼyh/0fn=<u47t ?a+jq|bB}mpyl k;銺kߴA;?H֚%ss®}GdQn1[[ B!LB!$@B!B!A! !B!BH B B!B!$@B!B!A! !B!BH B B!$@B!B!A! !B!BH B B!B!$@B!B!A! !B!B<@`aIENDB`bless-0.6.3/doc/user/C/figures/bless_preferences_undo.png000066400000000000000000000422401374060072200234300ustar00rootroot00000000000000PNG  IHDR{sRGBbKGD pHYs  tIME0ǯ? IDATxw|Mͽ1KB!;wUF)bSڵZtmEժJfRTbY"  >>|93r|g(!g!@! BGu坜eē-tY"Noa2FLC~)Vlgx(_o/傾㧟aCxkNd<#Wq(2C݌$B!$/c W2ЖdmkWgdff=jǚ4~4.TFxvu7sZ{,m*$pr)z3fZ?WYXFFy+%*<(ʹLIB<TlNJ\lRJ2@:<Ǐ9 ׈>ÊU8f8k 5JcQWRn$qB&|'7N!PPlǼw]rxh}i7^r"P.A{ޛ VX\]Nj7"h7e,}8wG/'30qj~b7ƒ/Y4n>;’2zb+_¾< ӉJ~ҭ  DPVm9}Wl#w삞t˄9r4;?+8y1 dWyP'X{ĉe/c}i_ ƌk}Xrvc9nk5_Ns2<BB a.Twã;C ew!⍙hFӐ3F-?fػj0jVZe{/hKu^bOqE'[X!$[ zdٛOTQM9%p!@:o MIq RR%Ž0ep˝BmerX 0[! JJ{*weƴ4+o喇8vKυܺ re9<$)Cr4I=p,ż[ \!Ev)kЦx&dG.8 e}@ӥ?~TH: '?u9m6'Y>u_wV,:ڜN})e+'; tਖP! j)0?w ]V~cɘnx6a{:YBܖ)76iRg'w%f5pʏ,ӊ^xccW nSw57[R44B0rËΐnl++A!c@.B!$PB!xC TΑw\! U!(P.9tt! L%uTG230} +j*̘1I(B!ö|=촅B񠡠t&Tv|a:zڣ}Z:s$ɔ[k5uVňtR秡E%+1r5:BR BR` 0̠RS1;YZ"8:Lhk*O&k7r*+w&_~!+7rO6Af!B!.'%0dWH2& F$XYSV fGC2䟐$+T4qx2Y+:,{"Bl}I1h0}ń f@6FLf#I0(7 8(OI*w|W9w4eYTƻ[`6uM*KKd 񴆂>0fPٷCekAGьœWg `5sVcgqcdF=&QL.p!bccJe]\]\VTR|9|j^ kyک !#W$\ӓ2h޸,K̘-os~8kAe :WqW^S^_#*68YEtDGG{N?*U¢|EF#aaصʔ-cdgg %5+3Y@ۦh̹HVB~oĥcQw_׊XO⪓uG#ؕ]*`K9A$Qu:=M%[XXPz TJKW=%!-k't4QF²R>C8/_:|8 k2qJ,nnOD 5ꎟ$&&ʖ!D돆|G~ܵYڦfSn Ν;3y$HPP/[l~zP4g@p56;hRwܴDGEgN6n\GCPT |`_c")S={ `ȑ2e~u㫤lS!hQ~JDZJ;IcJUOj5j0h(aj5 ?պra?ǿ|R►Z-ZRo)]E^S~#Z0M9?D`7dO?]۷B r~.+sTtUdff2i$cҤIdffҲu[ʖ-lj,-;8<ǏDYB;p.xss+/a(9f "?/xz}?Y+صܾR tΞ;Kn/0k,233С֭#((ٳgӴy ~WE{Mo*&.ux7;BHkv<#WtT̔3=7Y~fJ0]<^Ɯ~eF3{}((_,dV!ki;Mj퀶9-mf5RLIQa[dTI&*\ 5p~` ӗ$Nqk {nL 3' |^=ѿbԔ ^΀~)sQ!&# WquuVL&|oݺWW7.]X|$/3#6$?K-ݛi[u{1obgǎl_N2YOb] ,Ɓ)}ݕ塗 k,LZYMp]Wv^p?BdV?ƥ[R?R~zG_!.b[`^D}j%=പ۬(&$+B1wWqO: o )M483w.DZ P~ 66Vܮ?IJJa|>=>Nsy1x<3N{IS5Дs՜hBےH^Y$g[S溶)uvr7 -7+rz*㳬odH آf1P>(r1!4uW4<߭!"-j,4p=&W]тaZ DQ)h4ƣJU:uepCNʘL#ne75*KG\oNiQl݆$2xqͥ6C$KC8H4A)3,2X+ 7йKE.]RF{gۉ䍡hA0^r3]%mܾrF|-fΙIgHpl̐9٭jS} `V]ˇr#=ydNNN 8ɓ'p>7A/V( 2&r:fDS$j)[Rٺ c!= un@%" XO2aȥXX(? sǵ,]"'=QR(o˙&p !@1X]Û8މ g&$$fϞ {v ))u+eI7qأLtTfoü[[zO r0.|m UUsW #f_؉O'*0SA޵z}ԓG[ xL_l#ɾv >dZnԽ?3O%e4rmB<ݡ u=j>qQ+[k^ȱcGY;.t]`8~_^HfVf}Ӎ&Ϟ[WYSZƁf3W1FTBӟY3)ihs ?@G7?țS7=r -7}c5իзo vLNkJW7<ڼ^ϞԶ[4k`d*FԲ-6{mc_|kMgs!_}y'1(+>- O2<՛wlSJdļj Jű#•\\[ƍe[K3%_}[C^jɼ>|$9m硡~/oKޯzZK֮^E:u[r9c~d?]hhĊAU'-9g k}Ak ѐz?RB& AOzzZ$5KLN/kV>2eTʖ-˺5ǝ zt~o߇*VxѴXZ/"탞xjjr|:s13դzΣc}g㤚 v[94+</ύYm~9N9r(M}*!f3:tRSIIN&--쬬"8 G=o}N/kWJ*]}3ȫPPlhW,OCa$d,B>ē-tY"Noa2FLCH?N TElJp"aH0E9#?b8a(XuⅣ, zaēRp7>>>'>>w !d<l5܎UڭxeR_ 'YYŠ#inڱ&/8(TX\r|61é4/dX~'Y=Cf '-0|`l\3:9=6i8Zq%;;RyKsS8P*wd2T*e !~85K >tp43 p2.5"q*oR}r`ې߽ܛ*u2(2,?c2Nx{ڥ$hBsbE܅WbcbJ}]SSR0LE$]xOV(uV8hP#grxh}7?Qx@IFn_`\oO? ˟LʠML讜&VKY9!@mYl7Ξ9XzcQw`2HLH}4kѢO6B<ykFj"r&Ɍu}guҷy05dpk %vn9;d2Mx?$2~}Om)5޵kSn=,,J3*3M&Sޝ'B#}x"!OyB!$!BBB!$!BBB!$!BBB!$!BBB!$c2$59kI$.[+LjN)+qկ!H>صkmڴeHMNٓD8fgg ^թ㇍ *W.%.1&::>im)h۶-v*ٚnGl@p56[~zuԝf2yL^ lܸ %Bd,ױ#„Gq]@!G(ٳg d"-%{P'jZMUj 4Fذ~ jB!+N!PaÆ բx*p;? Z ?KEWZn[`Rl9N`iiY mW# ƻvK7sZ{,m*$pr) PVI,l*7cSijJMbc -GLt}ǠK]feyao~^P5ŝJv *m" Ͼr[-eU'(Pk.zɆ )ED: 濌>cL"*5*P ZS!:`ې߽ܛ*u2(ONaV]ˇZ}4o^5fSX2:&]2^ńWb{ulg Gc̛V6uo .t Tև>Hȁ! IDATϤ8t5X4qaŵ ݄ۧo9EVA}{RV~ :@ >_+ߧN_XZX7W \Bb@䃕/+{j}I@Xq#}}*F׉GQEbB-坜,Pp u=gءn?<_="ĒKՓ,9#9qp|E O|L]%g~9M7ǔ)⵾39./ݣrX ,,^Zi{DE^f1` zN W^Ƈ }Š&@ejuH_j ȣ[}L٘ʹutX8.?BH(`$aL^|f&`pNVnlؑ $&lXS,]t"C-Tme ׉_e[~HVW;3(1Iv?!$3ӛt>wvvGzݟMMW58{'j\Hv]./攫њh,γvj,~fL ok?V5* CI43s+Svbt%ժ`$~376̘3U5ygN^(תiprS-_2 Zdf+5Dɘ/g YӽQP@CY~?fuV{L~nm_pÈo cZS. '5oD K߯vzbj eծocgs<{3mr8 SuNO~";ۿj0}l㣆2=eVw6r7!Y:.I雉l0L؟k!qwz;Wqb(^fۧǡdĦ#>ӖZrWEG6/9Y~z 1Yrĸ,jk;YK܃}A'XTаǶLy^zU2I◯grGI,p9g?ʷW hiQ:P1섦t>sᨬ@,}5.a?MIБ]m '"ظLtr1GP J>t);o򶳭P.= x1x::xq"ex́4`s&/Zb;0v\;Ejĝ!Ndx4`imj3txK\]h5b +,Όo?C.)LB,^SZ;c/c낗4.߮0_g?H/ʻRq#8]l[6d·ey|:>_DqouYju~:@ڞ9US 8r=uV*1fɺz !@juyVؓ/C;Hni0'pMs5>or <"ɣ٧ Mn,o60,ڲ(̦C]RMn=^&gZ2Z\Dbǽ|g !1 'Qft"Ua+ܳZ27_ cJ]YPu0o4+S5.S(h8:o5I(8wKN@ڏn]SQDţX5>j$v2 ZԮkPNxKK V1>pi=Oeurk/_g`- DfOW0\モ+xiRz=ã@2Q9dCr4I=p,M8s9}v|{,#gw={*cK!K٫S@ 90'cX̑^J`b,d_¡rD2@a ! z-;̥+WI8 N;>-1l?o$[T%Yo!$AaWsi_po?KoBI36~ VlN^בMxձJ-b<?eGN^MGO%ERUԲiA2r=ٗO9|Os1 k P7c:(wP ?K/~ʶFSGƞI2~G~ՎOZܪd'4p,E)sCF4?Ť6Uq,yF6Uǭ2K3ܴTﴀT$v y͖T8MȺk2p\[(:&P]8V;U?!V1o: *p9g?*JA9-Oz+4]WO_߁K [w`ϴoߠ{߼T 7T|u1QD{0ۧB<)瓉 wr]KLx2+r㖺 B/K:% nR։BZ x꘲:AWUp*YBda\Y|F4  Y-BIA)v!O!BH(B!!BH(B!!BH(B!!BH(B!!BH(B!QL&Y&|-SewF)tvuB!y!(.[Gjr*gΞ$"> &AYoɼIkηdN! )M483r!P m&# WquZՍK.z.l=߆5etg7(q8a߲.Lw[I[|!~qR:"~^K_ohN!d{Ŷ 9.^!@[Xx}=x`0ح 9O@ Nu_I-/BH( tΞ;Kf5ktЁD5kMC 7LӋ 1YjD # GJ m^@IV6bb#CY u@6Gʏ^+E:;y`;9|94gex< wi6wLlɹy#U\gלo (BH(l2W7-[nd2a2BSw{6.4M\dN3kg4u֥)# vjNܘm-ޞ9@AV0v-37b.a&)BH(u sذa6lX:2R`GȅPd5M4ÉY!awGec5J.# }6>6;ثKh6%oLz{݉"e{.;V*KG\oGIG|\5S{BiH"*ÉZyí\jɈ&)Uy< j/7ļ9϶PO'q_J 4 DЩS;.6&*U1}D*/NLvT+E1lq-ӷu*3F.j*EOh`W\!B+)?7Le|Vmfs8l"Gʲ&|,ߓھ7>ʛ&*y BBP`w oػ{'666̞=BBB={6666ٵ$֭.;Rj3 bUu\38;& 5mcgOj߷~|ݺ2»o_|kMg+Y7~ Aǚz`[R@Xq#}}*F׉B~TjPbzJ6!@ Oy'gY+ص'& %W-m^2Qٽkiii 4B^ )Jc k^^Rֈ PwNؙ[8)U*T*ǎChhWbcpquïn=7 [-@>t ˷>=z6JP[ۜ茌[wKKKT(* 0M zt٘fـtI K@9ռP@ OT(B!7аػ{g^ A !@!C)% B!>(%@!&t!( !t} qR@B}PJHBMJ >BIA) B!J>(%@!&t!xܤ(& ]V6zшKj+KxB"Di>eHMNٓDggg ^թ㇍ *FB_ Di>e-?s=:]^i3v۽q>t9IDATvx9{QN2XXbb8{pGy u9c_;əlظɱբP`&SO1##:С=6LeW; ޥ7/Еɖ#稫KR-m\ee{n%>Δp{mTIkfSr=Zt"" dR| Ԉ3atNgÆa 2f*>\wϽOfb58hfZH7xg8%^Si S"EDB aigY4ɞM?|>_$3G=qy>)57}[L}ZjN0-yΤn#66K}]")y,]]CP}>Յ/]m}pLժ:Znv 6_~9YKjY#}m֚ÙXᤌOC}9|ft )YTCQ74vYg{A1ߞCK/nD̬,3r9+&FWDD4GtnP TVimm%-m2>@o4`܊mlogI/~ƶtsƑL⑥ҒRXr k@Jsl+-TV ;gOC0;`Сd~1P{vYl96 ϧ/RDDC܋g?V:: LJԩDD4Ƚ ] 6e,v6twyA}"":S`S |xivkWv@ "7v L}t 'Cd\@DDP| ""&P|`""j @DDBM B񁈈C(>PS|`""bP| ""DD$@񁈈OopK'IENDB`bless-0.6.3/doc/user/C/figures/bless_search_find.png000066400000000000000000000153471374060072200223570ustar00rootroot00000000000000PNG  IHDRA-GbKGD pHYs!3tIME 6XGtIDATxwXT׺  Ն-#b=MkjHĂJb/wX{ĊE-DCJg(羟<3{k֚TroD?K[65h8"{TU(+!u_* E83G `%<hD1_߀1/$]gٴ~ 9zzu FrIb!B+dæ6IuA¬B!%XaN/fNEQ &X+WJB!w5Uj\x8F^0+B!rEąxV{'Pb3 fsH%B޿ȞOeUpB!dq# !B 70+B!rmǏHٶǸ.+ [BlF2ےlr5P&,[4g*f.6kG 0+ [EF h-!,nڋܪmClaW|NRO,/FBHBaAVQdJWf#2"7cE1""УHHL4 +BlR5 YYW\CBBY-rjBӂJeZʃ;~bzto]<{^nFFSjT zA}zakk+{a !ZÕwי#/m'm&mN~9ژw߷*El/LM;^]"ǁ_٥h D?_k7%p*i^_zΫ(T #*:\Řt%HH#Gn|>j2v˞_oXnߋK9PHPԔƐ,[: |~^ӻ=G-Nbc'899}vKq1FGBB:Ȣ܎2mAPI7}ԓy㫥zӼ[wik"7}Ԯj4^/Kگ޵XO8-Y*U6{휢cOXvnĕIGdm/ǡD3={oXÓRӗY{Nվ c?Bq'l QݯGil)RڝvCoLw\ZP/P|qlm(р}} ( WϥlWɻzʒjto+f|xo:8!P{#"d/L?@؜0&<%hweۣ9tgO9K=փ<)gdP˴ndwKIW:.z%%u 7mYVКRzk|к-Zb9:u݋m_OY9y#i\kӪ@mTbMdqeT8=^Ushx BNrUҪUʂy ٝV%il0QѠ#qm`ƨ,^8:%1114$spq#p2q+kW0!U91xvAP!gڵiM29} kˬyI7n;'lٲ)cg30`1KMM 9Eι& h!.&YnE#6>.myyJ6i.Ow& ޤFE6#YVYCs(vžU-&$FP^ 7>`;vs]?Iߒއ,d^|y< Z˲M"Xޣ"}{%תOIl:v.M{8 +u'iݎǽ:;{C`FD8n^V+UʕbŊ}AO EA1*/* ʕ׷Nh4VXؠVf?BmUJ;'ee8WeRt̹ͨJ+ҴgI*aEFꄌeR_K]rܿ~ [r}֮?ݽ"Νgw3`ʔ)Yb5&·ؾ,Џrt0e≎|k탧5ZVtwK0dʿؽ\ ':_qdqF1fxR}֩&-6.jbS~Q[7y}NڴD?%^8JI",z~nX"m(Ai76m̀ixixM?x.STczp(&El-6N%/!4^_ۢv|%nǮhMK v:4!P_`tOS.At#W 7ӪxaqMv8? ԍ랲n{:< Ou:X]~߳:ˊl+aM<@RaccCB1l(/f玭lKB$ʠKލ0;pJ(V".e?TNXU8g_V6f-F AMi%Җӎ2zkx?}ARV1*7$ P^VnF"iҡۇ4p۬ 6•g(9" 0tL_F>ͣ]L[;hܨ!ӦLD=ƾ޸l܏K:?6_lY8 S݋r=Ekՠ);۰ B묞~7/Äw `$ kgGx(VۇC]r* QOF>'mZ½@Z-?#!@VϏF~C؟Q8QxV[ݙ߿:̾HEϝ3q|tmOؔ͋hYE!N8 xLmY#70@B~X0([ayΙ[#]8ĐUr߳껥ՙ#?VpBmm,Gq\RZ1wu HJۿG֦ppiο]Z; pQmai)".,ׯ\H͏c_'.Vy}w9qo_ӘROt~m&2d5WZ.mdτ5buH§i]4BÏckgy'G6j9Žܓ>'mڿsfU<h4ELY=?kз?u&^?#E%ܪZ464r}O9[+J7۞/~`eFcEqfo6ewx_T k[j_%ژgwKVВ+ZCVK)WWzw!;)ŻR`NÚ2r6'HbٜkƭK~iΪptAL>VbҞlٕm>IYDO];_iؾd4a;sݟRX[[Z\K&YW!D>&Dx5 RHaƍkZ|"4ygEzKj_ʯ RY>P&Ykkkj||$Y! >0URQTdś" myKBX|)_ѷIsn^ŧ +0Ah6J=2B WŔ0+Dn8xU}t-]&YH}U>OMZ BlA [BE5PB!DW7B!Y!B!$ !B!AV!BHB!BB!dB!Y!B!$ !Bav^a2\B!(*!BQЂX!BQX!BQ]!BQ_7#k$ԑ4i_7#dpB!̜L Q޵h .! u2~B!]Y٨6;4}4B!WCȞ*B!< nAVBlWB! C~0_%.vIENDB`bless-0.6.3/doc/user/C/figures/bless_search_replace.png000066400000000000000000000260561374060072200230510ustar00rootroot00000000000000PNG  IHDR[}3FbKGD pHYs!3tIME 8) FP IDATxw|99ٛ#$BlRf(RTXUwvlUZEĬ3f!"+9GHv {+uy\k!bddž B!o9;ܻNC=_i5֬C`q ۋynzTB!K{i3Κ4oIzD"!X!BEh֬Rh(B\Lt@҃.keiTԼB!xcm)8KDs$l7k}%\ 8QV]ZB!NZuq,JM+cjnbаB!PYUK!BcwR{PJ8!BE5C% !B"f6KB!oEJ(/)B!,zB! B!❢*ܺ;"D l{9&Q{ѷټ'xBH~ovR"m\$χ`9&3brt;}ցեq߰[1h,9FMH'"SX!Dμ!11\zSz a?*/Fիt:i7(lN=Oͺ Ϳ.kwde,$ !x^:O75rn^G`ecG rѵfVvZX 47lھ֝zHcRމB~,ڰE+, at?kTO9>,u^Y^ޥjX?T~y %?ܤRRL "U.s!SL^e=z PZR8XK|$\!a|z~=ѓ$JKxTcP=z$ҳ|5bbbQ,\Wvdur@Ja{b?~w7۱,FlG`1˄4+o^~uDFFJ%嗃ȥs(Wy-ϥs OZ.T(sܩ*O/_LLLR={9&6+Dz;7f&9Rw)64C#իW#5~"sD3O ;B'?Œj~1W, RM\"^ h 9~?ukWn?]1u.S5?)uvE&uz|16ݝ35ޣO>fVOtZ}^uQhX9#% bfiOmR1g3쭰wYi%;  3s ax15'wKzuԑ|ܸ>eQz=:KNj;RsK;6 “Qؚ2|׋[s}.=z՛.gOISgO$Y6ns$6+gSLg1<ӆU2M9{QQNř ^]R[t=\?"9k..&!KIzο/%@66sG&&&|P.2ۙL:^Oʕ0vt6nt{^l|˜3SÝY- $;zb sI.;ډmOT`Ѧ?x8ݬ71zF"Ν`ۢx3,vA-ą'XǓ'g3$INتl37P-vO:nJ՝"|jsbs-g/RXсKͣԉOS,%ΗlQލdbٶ}"-׽z~KQK8w$VN rLca7Ӈ7_6F@)-3?P,?+-UdFc^wKp s=ϞHuiLɷkjZ7jBܣĉ>s͚36~&;>['4eZIGCS2ҤCL=Gyx`4|cVGU̥uco`.o.\:JMщS˕c֌it@qf&tztz:V4SI_fޜTZ,΍IbIkFmտۺ]s4v.ǞWtWݑaooGfM)\؝cǎSjNur?۰ש-ժT|t2S e&eּ(hԖ_s w >[6j@->8GR<ϸnp33>^1Ԯ쇛s!≦2:Dµtu۔;cy,>V(Mi;v-8ic^ hY3fu㧃)f+ =ISę)։8s<k!z6A]LAyAPĔ)T5mKVk Ve$3W¹W;p., fQGoǥX4(MhK<cLcX)y+ϕvGƕXbo˫'Ob͏눌ؼ`ESgOp`FIath9E#5Tǯ<>~/$Ck~̀qǟ?47IWe^!glb1DyEeol<- Z]Wq Բ{QWH;N}9׽xm*, |GϞ>E;2:Wa(W6-fRibXn+pfE1}>EN g,wBʊþUO(OB@i" Xx>vvv#M.50iruL\t15(T鿭W?q2-*v3]Evi?G~c9XX^NO /(&؛(XZZbkk5ffi~iMyp+jxm鵕̙ɍ 7fk42}͎Ǐ4tʕ+QZh4/ e!jS鍻7 dE,UH=95(|T'6Ǝ9V~V*%Pw S+ĕ;_I}4OP(sm:?3jE:jdVN-nQ>3E}I^3S*xI{`gnImcBsnwكƍ/%<͐ATP8}VWhgšCfUJVTa˂4pcZ91k^hi8ͫO^9)G]8mQ/5a mKG)[f]rFWAPVWp]c,q*YK8;èZU؝ف 3 s*(eh2h7l ~+9)\SS 6 E#jC(bn{ lI .>M ˇOW]W8;=vNIa]nt'MoD'7(__`L_2d&$hdIYlSF,=Smco*b&}LȯVl [BIs'$xNYp]OiZ܉Ç$_y`Alll}'y鴕am *Qq^68ҭGŎ:2wLWlM8< =ũ18IVdX܀l ;Ac-n%*ktU,N=@dN#o^ֻ` BH9bQj _4bۦ|)$ʭ鈏'&&3gҽnXZZʰvy3RiЋ<)SX."Ga*sc1 ffXXXH#nLڗ&<BH@!DIeЌI!R)*BB<PF\ > B>Jm}.U6d%R"W,;rL#`Ѧ;6Rn#\!k<ս Y6wTȕp^D aT>*,􂟗/B!!B!$ !B!X!B B!BHB!BB!B!,B!`!B!$ !BUr+| , !rP޷T/[78w4X[Ff֟YK*W!]j79n y>'ߖ킥3be-u}6?3j<|E)kZo"ST)&B*[v6U}ɫ?Y=XDZcpvvѣܾrpFϐ1b?ǡs0f0oߑ zWroK-߻W|%,/_3%}~NVޕEEYE7@Ѥ^~uEFFJ%g71ҹSeʔO1ϫLyüKN:X/Znn.A7r5 * ޙy(_CJ0>ė+[+?~9F}7:.WLA#\2N6X8ǃPǝxeS Z56MOFbQNVw7~Ű03ιHQ; ;f8{Ѣ@Ëʉ}XKK[&܈CcZf[aeFӈD-C(hmJeK(S ˇw=vTm…'2Fmޱud7Or^}F+A`ؚ2|׋[s}.=z՛,tIr*$ϞLKp~ +W j˗;CQ4Qbkk˪UiR"5<]6&%Σ|m1ܶmV(>WcFˬ(+gpgn ©? ^X{{P$lؼ'Or1Nlì~/Nwc8F/HĹl[4}.Gr^P_fǃx¿݉wԨqJI-›odܢM\8{}<yrJV_!O9{8d>C:ep?(0i 6ӧq +bK,XboN|joX>y9 ~ME@>>Cm>A4hyo^=ɨ%;w]+'QSRB80#do3@o诔Tң,H}DtTK|\Ɣ|9#**Ao~lm??gnf*U`TT(1c&5#3c]P7+?zrLMRuX&LnS_DŽ 0;+'q{WuL1bYf/fM}J]fe&z9eD@WKps} ߺj1ex'Z^-H̃Vx<&83C $dؑK+R"vΠ ?7ij&!}{Z%& 2}iü~2j8%^xr0A,bdA0p{3sGJUib_<ƪOlcɱ>^LF}B(Tyr\!?/Z 7'zAbrSc%q|UN{F7ɩˠz5ziа>jxNN133c3Pdu\zQ4vvؤ,FmaSuV7>6{)t)&vc? A Onq9E΢PĖ!*G~G'){xPܯ9 )nf"' Xѻ摮 IDATOGj>r%]'43+_4IuޢT-#ƫ+֔J6t#5S eV<^a*5ޘkB ͧ NmF}d:uK_?w>L`G_D\^ԟ}-Jd4,xOcQFy8z?m{}M/Wfm|mKDlVT8`D>e"N'3ȩ!moh4С١tbna֍IE ÿ1Nޚ_~R)9\[=m,߫͝&;n2^''0s5{rh]TI~* d10Kt4*wޖ*j9R58=U/Gi7es/7Z&t8bQЋr֦l~Jk̅6썍CbdžajS1,Uyi۷6e4)$wHzetvfm`gt  ߷!?%˕}0[ l> 밉t_ӞzI%+ =~,ӷFϩ!Qu&/N˖-R2`RQ*,\0RSp!Oy'ḻ0GRabzBW~_Ǐ"DƧB91%G^ke3g欟>w.EpQ|:ź#nókrML9ؙtz=\fĔ'A 3T u0{t9^fS &Fޫiwr-&K7jzkO U&N P+KK,--0Du?W,3家(>jCaw7 pTea:\M-Kt87ŷ,Us]'F8[cFJMVˑѷ,<{yO\]] _oFgݽrb2F.ܘ&ȼ.?x)JW1[sټZVMMrTߑ[zdT?yXN tEkMXBѫu}JYױ*~J}ْP?:+޷}2ym0uw٪^S3Kv[ ,niS3Ss*5Ϳil8;èZU؝فj\kb(/N5'1 cjjAنx_PFjEqziW QK˕rFC{XxhEMp?}=ŧw6 g8gnT`[[WWW bccB:VKqv~Xi<%ǗzT*ù*!!ϻt;;; QP!ypΘA*t9ff]42=TtJœ1y7ߍʱ0c!m4 aɫ$R5N5ɟ#z|1c4+Haڄ[9;Nd3lXȰBrLD&$=nGʅ-QE[RBdCF7+ T&*t:&&&uZ-z=  4{i7T"h"ׂ&&+)uing_3Y{g 𳉙;'g`q9$V'BbT"#o7oq^$W\DzzO'6&&Nɳ'R?343NX_Gfo, f5[!+V'3b^\ V5\ BP$ʥ'>>+k[JxGI,BT3kͰpPY.J7%w0g&HU\p"&O1 !.sa`&7wlFF9Vf33SK]ZP M)[ȍ7\}K2! !< S@`C\݋H !$ !8/_J7[ B-J!B!X!B B!BHB!BB!B!rp.!BH*!BFHAEK׾VzB!F] ~kIAq1yaWKVB!H+Swr|:6B!0KoKX!B+1Qw2%zB!q?T~ B!r𛋤X!"o,7e8!VmЩ{ [gTN(mofX.Vn{q(ͭqقT{w !t,=3rҕ,^-s _eVS]t(~]?~\<*+;/I&iU`v8gn۞׭hq;*-O+BZmNCLapұc!c?}|TIENDB`bless-0.6.3/doc/user/C/figures/bless_select_range.png000066400000000000000000000116041374060072200225350ustar00rootroot00000000000000PNG  IHDR<-&bKGD pHYs  tIME  10IDATxyXS7P!(IT(u*u*Z-Z8֯b<Զ~Z:UVAEEZqVA#B@QdʁyHΔgd'8yR%1~K(A@/ݬA6{ BBA~> PPJm4/fO' y>[&c yAjA%(UB赪1%HT$Zn/zԔd@Rf %$"""zM0~ف>ARF(Ts;@C,05,4^6r;txNDPR 223K-0K+2@Ԕ$Ffie>ZS^YVuKgY1DDDDTdM 5Ŧs""""*"vfIDDDD LE& M""""]`jSd;IDDDڻ$f#ƉE&$""""DDDD2dH[YYY U9oE&ID:_&g@RI `o^x5~?F"EyJ!5Bv=ĉaI)X"zvrHRN(w|_&2%D-<~z췤*pXa-cPXd'F`P%2\Bj(Ŷ#CPDgOGuw T6o7|g@^cCZKLCF5B\b$0T%ll@$N[A J "*췆E&L""""29er"""? \&}A)&uڴB//;v"^]<_XZdEapiҺ+~] B|>J\7-׻hruuQU.NX|;/mۥ.6 J45ѱ 5"A=?;tD܎k$C(S_8WhL- [EL]K4Fg3|D\Xo/|W;3sܵ~!QOM-)mp<:qчNvvFmYX?7o^ƪo`'Df5Vqpjۨ%׫"dn01REoRŋ,0xO6x'KK#PfU;>es󸚐pg'/ޯ_ATY w b}_I`YLnݺFn#%R\,x>J̮Ro]Cz%ν[GLώ0m")@)oLfױ=hNL?7~N\Fvaj$kg0tބzB"LT1]ÂEKA>?{{P⋬03[t?>J򗮹d;^iV.oH)GD59K9olߧǻT\&GBMH]dF_֬ߌ\\]]!Jq%26ĨUp(ݒ V&&(G&SfEkku*z3UR]ye{ˊGW;,KG,- o4XLK/Ey$vFx,z,K.H5hR‚rޞ٘fZs&&0JNV":2|P$'+ae%+6Mgp1wh1۷73YP_)!3{u ޅCt]M q6= GӺ]b<|#4adڢZ%DfGkNU?YM 8c꣟K/f_Vߢ>F5ףޛ?Yk]D>qqq]\, Jy\d[OG8?17NB]Etֳ.P!)b~'ӱ7ёK\XU Dc>jV͇s&}u*>v)T3}Ԏ?qv[ZB^ʔe{PBu=)>yy"Mldgg]xJE[vζ r|jQ+00ubƇ#** qqq]{ԾunG@o/4k{NX| i5!ߴMG']`mέ"dR'f{a |la߼Z~h]1VWBW`KP/4vpgHA8t f.pnK V84g wptS  l~̶5a15AKHUd(n^*/YڭK\R& LLL.~Mչ4ebua:p0\  VV2ſH_C<8 Kwo?e^dC:;G-١(L䒲&U}M)$ O *-֗r&sa1qF,^s`Õ%D5P$QsF0"xvl_fXz] 1dI{Wz1(D\BT&G1?:~A "PhRgA<&BIt%5"?_` R)"H;Mݤ$ݤ$4~БU#(0T%܎'v9imX1T!@*U?APAxD&QN]ꙙI3HLTVe'vf@Xdicz®c_ OgPHj1[ђёu큣~:J 5Bu܎aIS3tnkm3Te2mڠ[m b%ĤADDT3q$""""DDDD"E&$""""DDDDDd^bEߗK.R֤FƭjNxɟQ#"""'ww7EfrKmY04+HRҔ5E #vM[J """e}&36ʩe#O2%ʚܨQ$"""fE7#DDDDիT ;ʼ=Ʃב$o4u&/X?A6j\3sf}Nn[]cx۫& * P Z'Di?Gϲ^gUs3a\1<v&RQbBܸiOw/_MG-An2!q,n]Q 'O@ Gz>FC5^%iuE k'ѫxwC|UŌd1ch=_/23c>N#{1sl|k4yV\+fm܌FLW׮zey ֮COHNo,j|L0*׶? /z+jKɷp)K=y* B駱Gي Ou;W?LHkW@+m^̸ eX6ǵ aQcȑE \2H Gp6<1 Ŏp~Lu.0<}(k93b`H7u*+c<wzzFMqͱ~0TlpXK_`bWh,3W>]\G;H%L5t =tcrEfc+j?[٣6esMlH(v>[2c4vt3hG@ La5"Fp艐]OGKÒG( hDLj1k#\X[m\jS] NMpIENDB`bless-0.6.3/doc/user/C/figures/bless_start_window.png000066400000000000000000000576751374060072200226500ustar00rootroot00000000000000PNG  IHDRH1 pHYs!3tIME /Z IDATxw|׽733;wK袘6L;ɍc_~NLsÓ&n4ƀզ*PAwJwBr}xZN93ٳgfcEB8q9rd2bŊ!?|9 ⮮.PNNF> 9˷oߎ׬Y3|ҤIZ+y̙>UoԻ.vfj0aB|||rrԩS<_|1==>mPܬ뛛322v{\\\cĉCObwڕ3yw^orJ1˲&3̙3ݻa[0dI.\H?qv{nnʕ+B(RRTsEeffc2le˖͚5 !Dt^^V+bxƔ .9Xf͂ ***z$oOL&\yMQ(!${ڵ].=0ҥK&NRM?y扢3DѤn޼ٓW\>>>(#<=}!Ν;'L8eـ|evرsطz?$ 6L:uԨQzĉɇoZ^n]jjjzzzO>~w)n r8q9r8o1"8y߇C>u/?/Y ♯͈͛TmmD5QM2C}6[Zg̜AΫe AC]J/fc7\v9%u&D*P k/4ƤDJi% <{8q_ XĂ h@Wh-EA0q>crӹϋ"Dq\bX60b{/u{c!y$a@.Gʂ)u-UUUUcjkkB3gluZ]r*FHp<Eq!dR:ۨSVWs (=9飢|nOi)o0qJUʵJ90/1‚ <襂zqFWQo%Էtxr|<[Ve܂ (tkIM} !PlV~ ̓dAOb/ zOi752!d۱W{ *R7LOI.f9^-?ro6Cµuu-V!::(/)8ԅ/z)Tg f!rQE v+}DdF)XcQDDz㥎)XqQ-V&1RR;XR+c<,m?p6o|z>upB*mh 5FuvvVtEZ-׊/NθMfbaA,U=bJsN+TY67Y[]BU7Q2 #R.=zUߺQt5G']R1x~޿AEAzS{o`$m"*5H%$X0&I"(XBS1D*2݊E,S%qSPRRvT)D'Bp CRc Z*WiY"C285RKF% mLVyy-\. $(VQD#a|+WFEN;)TCΚ>HwI!r ?g3!C> sW{"%QFrEc}1-}ƹg!n[h MDDXR3 نؔ@%6$[-WE*U>3NPɩo][eeF_!.]3ϟG4نR}ݩ]:u,E]]]b~IPL”1H+Fn#'Z,.V}Nҿ=u9>3oreomxfHlbFj"*s\q™&Ǐ~aﲒ]p2:qؔcG:f\| ȉ/XnT&NLzl~χ)+/tIQI3>^Rry}T4<6UAZZ6m44vXuM}O=qcom`)#Nɮ?.vt\3ƫ fw8:v,)}ԩc׋M /`3I㏥JOlqcO;5wY9Z;[* 3B5__8OwIu yWr*;rqCc Yk7LHCG:>U]rPOùJBGdn=]:rubjc| wYwS5XISaQA޲[}08Şŵ6T^wdϦ;F(GI(JѤ&\t tQQ1jOb0o}tRFJ__3"&R1cTbˍ0,h3GG]:[T+h 7 8Qdeѱ^lUJ YR $q2rߗcۧfLt ϐKsM& ~CG,=y҄,+OIht?$b!4mJVCyͻ^2'֗_zGvyyLzrOJTEh dCCt^]SٻcbXl7 r8NgjrZRQQQE\"IRO0,{fiZWtT7}=WTTw}i:6&V&2!۟ϙ@tmd2 _< N(h%2UEu}I&Bkǎ8|hMm-{`|Ζ}Ғ}񶯎Evm~(ޫy7S,ݾiV^ 'XyM[>eIϿ.>볡1ƻe7%$%{:yjmܾ흚3X$_~fx-WSRܼ/:up8n{mk_w\~RY`phZEA0Ƙum]5]tsK(}M+^YUY⒒X;r2۷oMÇކY3g̟?w_~U1B$ϓee%322bǢ=~p쵖-X!lٲYf}d2Ywi[~j[,ݏ .1yVE,bO뱏wBB\&N;ZIltbfҥIIIeeekJɬqKO q\.EƌcX'1F \LC}٧,"r(IIHQ Hx۬R  P(mmAN(J$T[kN N'>OK&74͟7_-n;!!A&+J`Xn_c( rl6:/}nRWOR%/}~͝;aDKS׉'"#Fp9~Zvذa?Ν;={ׁ}RСC۹s BDZ,s_~ϟUU ,"F /)Y/U[ M e{uMV%% T*H"I2,4b P(v~[!ˤࠠCj3 ςн)U*d2͛X[s\N`$IzeRolio߄/z|lƨ7yдXda\?jKr95T* I{|^яK~wRwnM "v|.A+4PJfxAyù:/BhFƈa>~쳎/U@H+yEAx9q p} 7\Ir_aIhOCD?ActtJ'_p:nWVTVWKDuyEŭ2kӱ}' u=}?yg/xgB 9N 0yc3"<'87 f4>]FK6:i9}e(B쁷jHOO[??>>NFH*2]QA!!=lGíeK; qVT6hvI9}E MΎSk+-E$BH#5"x4)KpYl eҰa>yy^Lh2^z#G)^]'B 8EK̛UXZ1q4|j$ԬIzY%&sB㳋nUGŤM|"86""`v3ra=\YФQ1oC[%QA_-|YqA1>C/|]9c( Ƣ5奰~tR404r8xc|W9^||F t2>t3'W Y' .ECqBRY@FV4")հ=5A+QxEC9vu6uy xb]3<-||ѶFeD|̶˧ A1'rS>|t3y1dĢG/K泦{NKI$xІփTL .nt !|"~ղBy%#]y BϮ"ƮZm+/@5j5\.\3V#7:rTjw4Sb! IDAT$ZB$IZD7BHD"EH@qis ÉrTJ)AJ0lN^ nIf? /,ӌh-B 1!GQ1nQ$BR1nVBN:Z-Y\Kev.A+zEGro؟WHFJgCNAMU}wI8!5bǧ~!eU0jB(uG$hƽɃFȼs~NC5:?1ݯcԧӧ%%&'&{^G$yJx>ZjI|~ I.4P`` B0Pw!x1ZJt&zM( ?hIIPq9r @9 @q r8q9r8q9r8@9r @q @8q r8q9r8q9r @9 @9n2$IJJJZZZRRҢErrr1n<O6mͽ'qFVVl1:yyy7n/O^|9od>l߳gOfffRRӧaeee_/ BjN0!>>>99yԩUUUZvGGGJJJJJ]Gp¼Zϟ7o^jd2 !&MJLL(--}w_yѣG hhh@M:… Cf^{HeeeDDƘeY9sx Y7x{{\ދ,((:th%%%77ove{Ov50nוS;ۚ%# @4~zՊ1X,}F}{_ߺuO>){\!$"EQ#Fhmm5gϞӟsΐ#G4<74Cw .$%%!YtivvvRRRYYĉ#?c|…-[lڴOyHNϤI M+zN;vlt֌i 5 `{zs^w!X @}JEFcժUk׮E;pF91r Bhʔ)ׯFNӒ⒛ ͅ7΍t d6:Z_2nlʉXV́b\}qw]BYmf(mmWuajiqYP[[[K[/bϲ`~Zo/\Zz sB2&,"l75JWƤZ88ݑMAmok뙉LHnsQA-m&*'M¥3?%f1)MHJlu8OsR;)'2ȋҍlc/ZgHC+SKc"^JŞ],"B^+2X4qCuFa[{;B쑽fQ`\O>?3<}ŕMڳwi,]]5%( wǜ9-x$s/E.5MmYpEe3-,Az(Z=~ >yÆ NzK,rĈt7fϐ6yS&=ֺsnZl]cQ;{˫g&AAA?[µ ' u}&h;{N!"t^^# _t---6lꫯ.]aÆ۷oذӨkvp<B("j5(~*^@?\H5ʟJB<EXTr, ڪ# I'A"<h!LJ |`׫8OVc]UjD'k`f0]r_s.R{、䄄7xpGGGVV:|v}قk׮ O> g}wB2~iӦ"L&`xW"##Ϝ9z7?x&uVdd$Ƹ|ҤI&I׿}LjflB[?E546g]]W_t" JJnpQEFO@:sS ",.7ö566rnFE8"FcrnXGUVOz?w۴i d{?/^|g&O? -[<3AZgRRÇ_~-[iӦVh4iZQA B?#Z^xjHib^^ ښ5*.Xk_Suc>*DvO?wڈlcFwzE 5eqoܼp̹>Z q ƢW~?6cCTO;_@̨̉S-hѢ'O 2C$KL6{m$74B+s[1(1rmNo!Tظwv {Z||\SS#WtRTdϭ\O 9rl fFOY䪽RlcmL_4*K1nBŠy_ynecȑcA]Yֲ  -[IJ~YSS  ;}4x۶m+W+WLIIyWBr|…!Vdɒ.]} a$",lZZT}tjc$)"ʚ^xٌѣBƎyfκS D qmmkrO/*2"g^>)N{ϐƭZ!4|^Zm'!X@OS\ޠ^=oV"Ξjϛ*Tceme\.V[t-AAAkV=Uqa1v%r!ѧ$Jٿ蠟2M( I]NHG{Mqm~_yF3g׼j|gwGYF>lxgkgq///^_ZZ:|L\+Wܲe AQQQ6鼼M&J깦*;;ڵk999ztto=Y;Lc.RK xP˲B(Wg7n'k_\* 7j2-?xg.Ms@\5Gďq^+O_ONL<<y?Y$IPnˁCGfL) 3Kʲ[a! 8x,DMarEe4ն;J+aB;kӲ29M+wO$''76nh2=ќb2<蘘ɓ'O6^@7_z58''',,gBaZZZBCCB999<ٳg{Ba dke o/PTC!fR*֪].L*1-{rٓ 3f(T*url[* xA0wtѹNBiƭRuӣOvvYJFR;*B*#,tvY> ip(NsH۝L&j<fLH>:tBFӹGWWðZ/8yE Pd8oopgg)e4M=gQ*fDj\^^q/KIaɒ7mڴf͚^{oV2eʾ}>8;v~a=zo=#e˖YV$i~{j @K}}}{mz7Jqĉ2yw~qt>o9(|gPi;wJ(R| DEL+X "jΜvKs>\£G[n5}S#| .sqKPh8=bplMZ*5B}?ζf(\ģծT_tH IV,,+iEljr`EToЮpq:lz6ɪ.O3i\"`.'\2jD'<~h}<%%![=_{}{ ܒ'9Ӷgn) 1w-] .?߾fC544֎7!TXTT*V[jJ ޽ccGX:z>lBHp;Ϟm}!W._꥖.dv-?ɅO"wNCy~IݗmTUUwY,i)w=>V9sfD"1 ~a]k׮=sR/zOU^^ϛfRy Xlf󽼴UTTbi8WPSVR?_b"EJ!bgrOjrښ}STr !Tp|o6y֖#G 3J,,*;yAI!!>P*n))y9M.\ x1+ /U*O?YEvDS~?Ё/6'+6nlvK?>5 A?*R9;78`GIGD;|4cb͎^ؠÏ>P(v]\\\PPvڞ.SZ.,,\n]$?+3C៼ XRiz饟O͚\J)s;-zsB{fBQIbsɢKOȗ=Nɚo/P]# BbB¬3t:]'kkN:ڎ\/0eȺ ||l Q߾/((h+DT\Jo]Ez>cT1zXG+'$!\Z2i_Ŋ51KCF3~ dqOXׯZc.zz.5kVIz:DDL΢ȘAM<}l=_{"/9buZs9w UյuS2F;|"Oa ^X9:bJRS\ɚ<'yÇ-|bB4B`钦֮_ _BER$BK3:i8a!Am~!Q!^rSv39uJNO0Nʈ-A}zMm蘠?..7߯ل%Fo-!a> 9q˲~<~Сyܹs„ 'h47o1##ic?Z[Z.^1>iO>>>ۿ?c4_{|펁Bz%11מFDzV"$,{ t=+߮/Kh:k??_?gi4p>*,AVBQwaOjzݺu3gO8+{O۶m{HJo3+1v7`iW6 `]N9!f+bv)U?\oiDcP[r; 2b8q- `Ed2~1}J" r~|E;h:(GPKS@ihDO~nGqlխbJ㈘8ɣY&͍ueoAZ9Y;GzQCMnTdU'/Wa/tتo=W^:l -Xw $xud$ H$$I#`kCxĿ!TU]SpFwn;z~ᅨBX87mm6xjjny]XT\S[[XT1Wrr#kfmUO dA[ E CCB_?1Ptld]PbK?ߺq Ə5cG7,ޝ7q?RK}/l˛,[ްb`IL;uT*of޻~HM1ۭ{˼;30Ld6}6hdj-8 !8ί(49>>?Lٸj5޵?q w~cBs/W_ǵ*wTWE*JlZUyFFFN>cVSS Ǩ''[J=iDGW;txatLIa?(EZ;=˓]4JyX-ovnn.8rHgglO [7y#Ӌ+?RLHMa$@Q;-[5I&'1HMNǕ%LڨTTb!/N&$@*[urU"Xg Vmpl"Ԥgg%tyJX_OWn̻a,SdI?>5~G_Xg{GS7l4RΗtYg HxZѠϺwvlFdgWS*H?A JKW" Mguʼ$G]l^^wC>N&}~TtnQ*ݻS`Դlr9]E9] F~^%U{P&soq8\BsdgKW"QL]rdoy A:̉.ݭݣSJ/_t}Xkc5UյC5oO,NΊDBEϝ;'I*.@dWoT_畟tP=5Ë":[rrkPi]8pZ݁}{'L+9\P3Oi`<\[b_񯚚{']mݟ"]oŸ]Y-./ͮΎѱT}Y5'qOnj s+nsC>[2[JEm}}wʶ޺0l˯ؓ> Jeiiɛo)Ũ&뇞NshK9v?`!Nkt5|ʹP("Qɖbf( N?{z ,+Y\ꁚ nzڽƜo UnwxP{Eaz|kp䩓ӣ}g`diڱh!{~m\6st=LIqtL\dۧjЍ3@;uIjc X=}xE2S^HQ'Lߞ^d[{yn{ R|nv/T'VWW/x43<ի+Zպ[I} qē/`L3T ,f&GFnK"OΏm@"h;zFOP|̗^|aʕze 8V콓O H40?5 c׮{83lrlV?[Lkv7j9|D~^a35|PvK*$4&Sdy m׿zLZE}?\:v"MhtEBr=:,SS _UC5\nɖG2Ν;x.\'Ls¸7y/98J\ԉs͗w1wC "v/@o 0ʤ=vEW%=O/L:NXtfCLVdbtAѿx }>iBڶj4WV㼄M7.'&au-e1t EQ& qq33g~VB6fZq-K 4%]>31~z[Ƃĵ^m4-LkTعflh(ܫ6@|:-b yl`!iKT'&&3RT(\1iR&+-v*_斬+y0X,ΠGVhwq/~̂Kk<#h4B$h$e|\9t`V-M;OG/HQԲ3qq/*X0:Cڴ8^Kpz.)A`:<Ξ2!76pDB!elóOZcH;m+ʟ4{\]F~AnۭfiBZ.+Q!-V%NZvdfe+rgB$ubC$כ~TPH>:OUUQβΌu]\\Fh4)~Ni|Cq90ddM'&9˯`0X, , qb0ۜrh(x3*КO/]tD))奆[u%l6,8ٜxeW{Nh͡OGV't$l͉D6@뺂q(A~c$Kqq͈a=< 8_ ǃ?%a{or4$ " JcOKgqxQ #(dp APH$(?6(F)X($| &ǡ%EBXD7.LhpA֍cͭ|}[\vsݵ{7FƆ= qi޶aV706s﵄ n44vݎ<~պfϽۇGF)}#W0bXm++ __$řW?klCc8$b|h{FTWNsZo[uI䪫p`53=]) 2TɥO|b+_;8WPQuzc5hHXLb3wgHI-RJݹ3/j/f=<_2yX*X]\ѪqJLj3=.Ҟ\T}8{QdzfV/kǸҢљ( >TCü?"'v2d3i [2M*0̳bYNaȻA2ZPYf۷fS,I$b4M_oJQpE"QK[c^"GDB 1`ڤ^&ŠTt$IڞaթTʙeR%Zۣ8wjEBh4:MK!MMiC(/j9Wz{{-$27iv$16O8Y9]}0l.Ly;9]4H$BD*-V@DVriRe:^=PTRx<.h>W?;9 IS32=3;;7NJ0,>)YFT +sEd@ AC!6q"I4B4̓m.^;%]9BiřR|>^f#AEE"gnPq:B1  Q2B~ AvCpd"( p8ģQɟRLFc\ Eilb&Aտ &NQIh}xqQފD(X itO8}G7m8p A8A8A8AAAAУS\!` q6\Z^뇼kw2,JamC8Ak\.}}}f`0|*I`7!諅B!/ve `p۶mtyyy333poGl6+kpk4PRRb2%%WVVfD"я~TTT?`A(HN<$IQd Bf9ŋkjjd2I$c].p\E$ b?(ٳO~H>6 tx%uo֫x_0WG);vd2> 8qR8GM=Wz^ߵk`---۷oEW|[ZZ_{__>Wp%+!8>Ayhh(>>f~4P(T*c=؞ ݻwz^ZZ*..~W~4776^|{m۶ o_ 4曱Qcǎeff쁁g b߾}&WWW{v ĉnEQ x D"X, r_.wAx*A0CA0CA0C8A=n ӌc{/IENDB`bless-0.6.3/doc/user/C/figures/bless_tab_close.png000066400000000000000000000123461374060072200220410ustar00rootroot00000000000000PNG  IHDRJ/=bKGD pHYs!3tIME %7ԴsIDATxy\Tw`aUV*䞕K侼_\RUZR-˾! 0,?ddQzܹ9>}9j ^)JM!(E""gI *Tݑ,J$`7,I%9%V)K_Dm;Tڲo:R&%O';~ʍ8xxsD0˯}M+3í,iIׯ۬č9*euCnz@7#[E_sLC c }km\\ r_u%#n#~Pl_ e<Z`s}A_歴}ʖlu#e{Y=|}3r d^o)&&2~eؙlM Wƴ܃sgD*k2\c@.]m=z۷o]y/VU Z7Ѹs;|PGGRz}U(AVkt ]V=JWdggsmG8_yי#3vI19ůz4'Z1Fg˲n|BZYy7¹F6!u~6]ٚ_dE?ϒtӽMgVWIessBg^nXYI$nUB>hǨzT)8gIgGB%ݘk<7?w)W6ѥNh9J"sfnD-&|C|魱}G| ST7V{<~ iԮVKɾl}j?R*sR>YIsϘқ\eIH3YFUHlF%/LCf+` k7SX\=3)Nw5?Qx7̡72 `xx8BZG8φS*͉0Y,ܺzS+۽:\\N)O A+%^OfX^ٹX]t`NlبNKl+ɝ?#cGQZsECDi;{Seiȕi(n Ʀ1"Rκٯ rH߅~=ڳ_vYoD=*o㕠 .ne(!heuM~75±CnI;;mY^|$ EQYARѡ(rjPu%@qjUt}uVC_\0,C;&DP v ,$/A=<؈ѳfFRrz{IRi`lsm}% *0ٵ܌dg><߯?ryzW^ϗ6g.\\\ꫴjӦFY"h }X9c"{; t"'L93g{+ILiM{иu8}c&.S1})Swi15&ds)πhAfP_)C&C0[Y,3ffO|zWzYh۶r+B7S8f}0;1+$qP&#- st̼z^~oOGۦ5jDNؖtZ4 (>/reY?F-Ofi+6#;馏XP(=_U_YͤBPԢݐyhӶ)+ˉ8at7/07=7Wr5a t y ӧm*$hVVѣGӬ &HjEGJ&|?y,GLaULC }Z&`e9+KH\";rp/nՃYpă5{#)kyzN{^PPԖFx b|Εs٩5Mim0SnYY"+YVڽ`<ۦ|Ђ233PȄRupBffCw鴗 (h}7e_wEk&а ™ +~dqqUǘf2A>-UIwWҊ)Isf-,L@f2#3S0[X2{U|hу7q"1cyyVF4S+'kvAϟOޡ} Ll"i=" 6 `~Yo<6 %,1ay<#tx^1QѼ )yFvmga=Y!1L`vZZnM1&RLF '7\OAI?1cԿIN)kI,{s/V=bmeZf c|QNIb17.Ìy[i0aMe9}d5wWHNWWWF0̜3i`ٴxm 1׵ž^BB]oG`%(9C1+ɓ'mG`2#̜2MN!ÙrzAMʘ&ѳ5! s$ׂƲiz*`\s6lVfX@Lcn/HϳL^TX<{P 0䥗XcT05r%wT^47bVLBBoiW.KJAAխۄ; 5o&_l5 .,3(mLj}!g#$''C9{3jժp 7E772~3&wz=j јL&֬Y$'df3vﮰr(q+^tQv~^OרVw@i"""Xx1u Bless"> ]> &app; &appversion; Manual 2004 2020 Alexandros Frantzis &legal; Alexandros Frantzis This manual describes version &appversion; of &app;. Feedback To report a bug or make a suggestion regarding the &app; application or this manual, please use the Bless bug page. Bless Introduction &app; is a binary (hex) editor, a program that enables you to edit files as sequences of bytes. It is written in C# and uses the Gtk# bindings for the GTK+ toolkit. &app; provides the following features: Efficient editing of large data files. Multilevel undo - redo operations. Customizable data views. Fast data rendering on screen. Multiple tabs. Fast find and replace operations. A data conversion table. Advanced copy/paste capabilities. Highlighting of selection pattern matches in the file. Exporting to text and html. Extensibility with plugins. Building and Installing Bless

&app; &appversion; requirements The main target platform for &app; is GNU/Linux. However, all the libraries it uses are cross-platform, so &app; should be able to run without problems on all the major platforms (GNU/Linux, *BSD, Solaris, Win32). To build and run &app; &appversion; you need: GTK+ >=2.8.x (Included in all modern GNU/Linux distributions, http://www.gtk.org) mono/.NET runtime and C# compiler >= 1.1.14 (http://www.mono-project.com) Gtk# >=2.8 bindings for GTK+ (http://gtk-sharp.sourceforge.net) pkg-config (Included in all modern GNU/Linux distributions) meson >=0.46 nunit and nunit-console, if you want to build and run tests xsltproc and docbook stylesheet, if you want to produce HTML documentation Development is done using the latest stable versions of the above libraries. Although using an older version may be OK, there is no guarantee that there will not be problems.
Installation guide If you downloaded bless as a distribution specific package (eg .rpm, .deb, .tgz) follow your distribution's instructions on how to install packages. If you downloaded Bless from the git repo, or as a source .tar.gz or .tar.bz2 package you will need to build it and install it manually. The building and installation procedure is described below: Overview: git clone https://github.com/afrantzis/bless, meson setup build (-Dopt=val --buildtype=type ...), ninja -C build, (ninja -C build install) Step 1: Get the source To get the latest source: git clone https://github.com/afrantzis/bless For a compressed tarball use: tar -xf bless-a.b.c.tar.gz Step 2: Configure the build Enter the directory created in the previous step (bless or bless-a.b.c). To configure the build and check that your system has all the required libraries use: meson setup build (-Dopt=val --buildtype=type ...) Use the --prefix=PREFIX option to set the installation directory prefix. By default the prefix is '/usr/local'. You can use the --buildtype=release option to build bless in release mode. By default the debug mode is built. Step 3: Build the program Type ninja -C build. This will create bless.exe and the necessary libraries in the build/src directory. You can also use ninja -C build test to run some tests on various bless components. Note that running the tests requires the nunit-console binary. Step 4: Install the program (optional) Become root and type ninja -C build install.
Getting Started
To Start &app; You can start &app; in the following ways: Applications menu Choose Programming/Development Bless Hex Editor . Command line To start &app; from a command line, type the following command, then press Return: bless filenames where filenames are the names of the files you want to open. If you don't specify any files, &app; will try to load the previous session. If that fails &app; will open an empty file for you.
When You Start &app; When you start &app;, the following window is displayed.
&app; Start Up Window Shows &app; main window. Contains titlebar, menubar, toolbar, display area, and scrollbars. Menubar contains File, View, Settings, and Help menus.
The &app; window contains the following elements: Menubar The menus on the menubar contain all of the commands you need to work with files in &app;. Toolbar Provides shortcuts to the commands that are most frequently used when working with files in &app;. Data View The data view contains multiple tabs that display the data of the files you are editing. Conversion Table The conversion table displays the bytes at the current file position converted to various formats. Statusbar The statusbar displays information about current &app; activity and information about the current file.
Using &app;
Working with files &app; supports multiple tabs in the Data View. Each tab contains data that belong to either an existing or a new file. In case the data is related to an existing file, the file's name is displayed on the tab label. Otherwise the tab is marked with a name of the form "Untitled N", where N is a number. When a file has been modified since its last save, an asterisk "*" is displayed next to its name. &app; can currently handle regular files and block device files (eg /dev/hda).
Creating a new file To create a new file for editing use Ctrl N File New . This action creates a new tab with an empty file.
Opening an existing file To open an existing file for editing use Ctrl O File Open . You may also open one or more existing files by dragging and dropping them into the &app; window. This action normally creates a new tab containing the opened file. An exception to this happens when the tab that was active before opening the new file contained an empty file. In that case the old tab is replaced with the new one.
Saving a file To save a file make sure the tab that contains it is active and use Ctrl S File Save . To save a file under a different name or at another location, make sure the tab that contains it is active and use Shift Ctrl S File Save As . If the data in a tab isn't related to an existing file (for example if it is a new file), the Save action actually performs a Save As action.
Closing a file To close a file, make sure the tab that contains it is active and use Ctrl W File Close . You can also close a file by clicking on the close icon on its tab label:
Closing a tab Shows how to close a tab using the close icon on its tab label
If the file has changed since the previous save you will be prompted to save it.
Changing the active file You can switch between tabs, therefore making the file the tab contains the active one, using a number of ways: By clicking on the tab label of the tab you want to switch to. By pressing AltN, where N is the number of the tab you want to switch to. This method works for the first nine tabs. For example to switch to the second tab you should press Alt+2. By pressing AltLeft arrow or AltRight arrow, you can switch to the tab immediately to the left or right of the currently active tab.
Data View basics The Data View is the part of &app; that displays the data of the files you are editing and enables you to manipulate them. It consists of (possibly) many tabs, each corresponding to a file you are editing. Each tab contains areas that display the file's data in various formats. An area can be one of the following types: Offset Area: Displays the offset of the first byte at the specified row. Separator Area: Displays a vertical separator line. Hexadecimal Area: Displays the data in hexadecimal number base. Decimal Area: Displays the data in decimal number base. Octal Area: Displays the data in octal number base. Binary Area: Displays the data in binary number base. Ascii Area: Displays the data as Ascii text. The types and placement of the areas that each tab contains can be customized with layout files. See for more information on how to write and use layout files.
Selecting the active area At any time only one of the areas accepts and handles editing events. This area is said to have the focus. All areas except Offset and Separator may have the focus.
Cursor in focused and not focused areas Shows the difference in the cursor when an areas has the focus or not.
The cursor in the focused area consists of a horizontal line under the current byte and a vertical line just before the active digit of the current byte. In contrast, the cursor in a non-focused area consists of only the horizontal line beneath the current byte. Changing the area that has the focus can be done in two ways: Using the TAB key cycles the focus among the available areas. Pressing or releasing the left mouse button in an area, or moving with the left mouse button pressed into an area, gives the focus to that area. If the area can't accept the focus (eg it is a Separator area), the focus remains unchanged.
Scrolling If the file you are editing is big enough, only a small range of its data will be visible in the Data View. The size of the visible data is called a page and changes as the &app; window is resized. To change the visible range of a file's data you should scroll the Data View. You can scroll the Data View in two ways: Using the scrollbar that is located at the right side of the Data View. The scrollbar is visible only if the file is too large to fit in one page. Using the wheel on your mouse, if it has one. Scrolling the Data View does not change the cursor position.
Editing a file
Basic editing operations
Changing the current cursor position You can move the cursor in two ways: Using the keyboard Pressing the Up Arrow key moves the cursor to the byte just above the current one. Pressing the Down Arrow key moves the cursor to the byte just below the current one. Pressing the Left Arrow key moves the cursor to the previous digit of the current byte. If the cursor was at the first digit of a byte, it is moved to the last digit of the previous byte. Pressing the Right Arrow key moves the cursor to the next digit of the current byte. If the cursor was at the last digit of a byte, it is moved to the first digit of next byte. Pressing the Page Up key moves the cursor to the byte which is one page before the current position. Pressing the Page Down key moves the cursor to the byte which is one page after the current position. Pressing the Home key moves the cursor to the first byte in the file. Pressing the End key moves the cursor one byte after the last byte in the file. Using the mouse Clicking on a digit of a byte moves the cursor to that byte and digit. If the new cursor position is outside the currently visible page of data, the view scrolls automatically so that the new cursor position is made visible.
Moving the cursor to a specific position To access the Go to Offset Bar use: Ctrl G Search Go to Offset .
Go to Offset Bar Go to Offset Bar
To move the cursor to a specific position in the file: Type the offset in the Offset text entry (in the desired number format). if the typed offset starts with '0x' it is considered hexadecimal, if it starts with '0' it is considered octal, otherwise it is considered decimal. Press the Go to Offset button
Selecting a range of data There are three ways to select a range of data from the file you are editing: Using the keyboard Position the cursor at one end of the range you want to select. Hold down the Shift key and move the cursor to the other end of the range using the keyboard. As you move the cursor, the currently selected data range will be highlighted. Release the Shift key. Using the mouse Position the cursor at one end of the range you want to select. Hold down the Left mouse button and move the cursor to the other end of the range using the mouse. As you move the cursor, the currently selected data range will be highlighted. Release the Left mouse button. ...alternatively, while pressing the Shift key, position the mouse pointer over the other end of the selection and click using the Left mouse button. Using the Select Range Bar To access the Select Range Bar use: Ctrl Shift R Edit Select Range .
Select Range Bar Select Range Bar
To select a range: Type the starting offset in the from text entry (in the desired number format). if the typed offset starts with '0x' it is considered hexadecimal, if it starts with '0' it is considered octal, otherwise it is considered decimal. Type the ending offset in the to text entry (in the desired number format). if the typed offset starts with '0x' it is considered hexadecimal, if it starts with '0' it is considered octal, otherwise it is considered decimal. Instead of specifying an absolute ending offset you can specify the length of the selection. To do this type the length in the to text entry, prepending it with either '+' or '-'. The '+' or '-' specify the direction of the selection: '+' means select towards the end of the file and '-' means select towards the beginning. The selected range always contains the starting offset.
Selecting a range of data has another useful effect: all the patterns matching the selected data in the file are highlighted, thus providing a quick way to find or emphasize patterns. The color of the highlighting can be changed using Layout files (see ). This feature can be turned off in the Preferences Dialog (see ). The patterns matching the selected data are highlighted only if the selected data size is at most 1024 bytes.
Toggling Overwrite/Insert edit mode By pressing the Insert key on the keyboard or by clicking on the edit mode statusbar, you can change the edit mode &app; is currently in. The edit mode determines what happens when you add new data to the file. There are two available modes: Insert Mode The new data is inserted at the current cursor position. &app; automatically makes space for the new data. Overwrite Mode The new data overwrites the old data, starting from the current cursor position.
Edit mode statusbar display Shows the edit mode display in the statusbar
The current edit mode is displayed at the far right in the statusbar.
Changing the statusbar number base You can change the number base of the information displayed in the statusbar (current offset, current selection). Clicking on the Offset or Selection information in the statusbar cycles among Hexadecimal, Decimal and Octal number bases. You can distinguish the current number base by checking the prefix of displayed numbers. A "0x" prefix denotes Hexadecimal, a "0" prefix denotes Octal and no prefix denotes Decimal.
Statusbar number base Shows statusbar information in several number bases
Modifying the data You can directly modify the data in a file by using the keyboard: Inserting a new byte at a specific position Make sure you are in Insert Mode. Move the cursor to the first digit of desired position. Press the keys which correspond to the digits of the desired byte. Each keypress automatically moves the cursor one position to the right. Modifying an existing byte Make sure you are in Overwrite Mode (only required if you want to modify the first digit of a byte). Move the cursor to desired byte/digit position. Press the keys which correspond to the digits of the desired byte. Each keypress automatically moves the cursor one position to the right. Appending data to the end of the file Move the cursor to the position just after the last byte in the file. Press the keys which correspond to the digits of the desired byte. Each keypress automatically moves the cursor one position to the right. Each area accepts only certain digits (eg the hexadecimal area accepts only 0-9 and A-F). If a key (representing a digit) is pressed in an area that doesn't accept it, the keypress is ignored.
Clipboard operations Bless features an advanced system to handle clipboard operations.
Copy and Cut operations To copy the selected data to the clipboard use: Ctrl C Edit Copy . To cut the selected data from the file and copy it to the clipboard use: Ctrl X Edit Cut . When copying or cutting data, that data becomes available to &app; and other applications as well. &app; can offer its data to other applications in two main formats: Raw bytes &app; can offer the selected data as raw bytes to applications that can handle it, for example other hex editors. This is the format &app; uses when interacting with itself (for example when you copy from a tab and paste into another). UTF-8 string &app; can offer a string representation of the selected data in various number bases or UTF-8 text. The number base is determined by the type of the area that has the focus at the end of the selection action for the cut/copied data. For example if that area is hexadecimal, the offered string will contain the hexadecimal string representation of the selected data. If the ending area is the text area, the offered string will contain the UTF-8 text represented by the selected data (if possible).
Paste operation To paste data from the clipboard to the current cursor position use: Ctrl V Edit Paste . The value of the Overwrite/Insert mode, affects the way paste operations function. If the mode is Insert, the pasted data is inserted at the current cursor position. If the mode is Overwrite, the pasted data overwrites the data from the cursor position and on, as needed. Pasted data can originate from &app; itself or some other application. &app; can accept data in two formats: Raw bytes This is the format &app; uses when interacting with itself (for example when you copy from a tab and paste into another). External applications that offer raw bytes are usually other hex editors. UTF-8 string &app; can accept data as a UTF-8 string (for example, from a text editor). It tries to parse the data and convert it to raw bytes according to the type of the area that currently has the focus. For example if the focus is in an octal area, &app; will try to parse the string as a sequence of bytes represented in octal format. If the parse fails, the data will be inserted as UTF-8 text (as if they had been pasted into a text area).
Copy offset(s) operations To copy the offset(s) of the current cursor position or the currently selected range use: Ctrl Shift C Edit Copy Offset(s) . This operation is also available in the pop-menu when right-clicking in the Data View. If there is an active selection this operation copies the start and end offsets of the selection to the clipboard, separated by a comma. Otherwise, just the offset of the cursor position is copied to the clipboard. The number base used for the offsets is determined by a plugin preference which can be set through the preferences dialog. See .
Undo/Redo operations To undo previous actions use: Ctrl Z Edit Undo . To redo previously undone actions use: Shift Ctrl Z Edit Redo .
Exporting Data &app; features an advanced and customizable export system. It can currently export data to text or html files.
Export Patterns The exporting is based on an export pattern. The pattern consists of string literals and special command strings. The literals are printed in the output file as they are whereas the command strings tell the exporter to do something. Commands strings are enclosed in '%'s and specify the command and its parameters. The command is specified by an uppercase letter and the parameters by lowercase letters. Each letter (whether it corresponds to a command or a parameter) may be followed by an argument enclosed in double quotes '"'. Command Description Parameters [default] Export (E) Writes actual data. E: the number of bytes to export ["1"] p: the prefix to write before each byte [""] s: the suffix to write after each byte [""] x: the separator to use between bytes [""] e: the string to use for not printed bytes (due to alignment) [" "] t: the type to export the byte(s) to (see below) ["H"] Ignore (I) Ignores data. I: the number of bytes to ignore ["1"] Offset (O) Writes the current offset. O: the number of digits to use for writing the offset ["8"] t: the type to write the offset in (see below) ["H"] Export Type Description H Hexadecimal with uppercase characters h Hexadecimal with lowercase characters D Decimal O Octal B Binary A Ascii Command strings can be grouped together with square brackets '[',']'. After such a group of commands is executed the pointer which keeps track of the next byte to export is reset to the position it had just before the group was executed. Some sample patterns and their output will make things much clearer: %O"4"%: %E"4"p"0x"x" "% - %E"4"p"0x"x" "%\n 0000: 0x00 0x01 0x02 0x03 - 0x04 0x05 0x06 0x07 0008: 0x08 0x09 0x0a 0x0b - 0x0c 0x0d 0x0e 0x0f 0010: 0x10 0x11 0x12 0x13 - 0x14 0x15 0x16 0x17 0018: 0x18 0x19 0x10 0x1a - 0x1b 0x1c 0x1d 0x1e 0020: 0x1f - [%E"2"% %I"2"% %E"2"% %I"2"%] %I"2"% %E"2"% %I"2"% %E"2"%\n 0001 0405 0203 0607 0809 0c0d 0a0b 0e0f 1011 1415 1213 1617 1819 1b1c 101a 1d1e 1f
Export Dialog
Export Dialog Export Dialog
Export Dialog Export to file The name of the file to export the data to. Export type The type of file to export to. New types can be added with plugins. Export pattern The pattern to use when exporting the file (see ). Use the save and delete buttons next to the pattern entry to manage the saved patterns. Range The range of data to export.
Performing bitwise operations To access the Bitwise Operations Bar use Ctrl B Tools Bitwise Operations .
Bitwise Operations Bar Bitwise Operations Bar
To apply a bitwise operation on a range of data: Select the range to apply the operation on (see ). If no range is selected the operation will be performed on the current offset. The selected range is displayed at the far left of the bar. Clicking on the displayed range cycles the number base used to display it (Hexadecimal, Octal, Decimal). Select the desired operation from the operations list. Available operations are AND, OR, XOR and NOT. Type the data to use for the operation in the data text entry (if applicable). Select the type of the data from the data type list. Press the Execute button to perform the operation.
Customizing &app;
Configuration Files &app; keeps its configuration files under $XDG_CONFIG_HOME/bless (usually $HOME/.config/bless on UNIX based systems and C:\Documents and Settings\User Name\Application Data\bless on MS Windows systems) in accordance to the XDG specification. This directory contains the following files and directories export_patterns Keeps the list of saved export patterns. history.xml Keeps the list of recently opened files. last.session Keeps the state of &app; the last time it was closed. This includes the open files, the file offset and cursor offset in each file, the active file, the window dimensions etc. preferences.xml Keeps the user preferences. layouts/ This directory holds the layout description files for each user. See .
Preferences You can edit the user preferences in the Preferences dialog. It can be accessed by using Edit Preferences... .
General Preferences
General Preferences General Preferences
Default Layout Layout File The layout file to use when opening a new tab. If it is left empty a default will be used. Use layout of currently active tab if any If it is checked, &app; will try to use the layout of the currently active tab for new tabs. If there are no open tabs, &app; will use the file from the "Layout File" preference. Misc Default edit mode The edit mode new tabs will be placed in (Insert or Overwrite). Temporary Directory The directory to save temporary files into (leave blank for default eg /tmp). When a file is saved, it is saved into this directory and then moved to its final position.
Undo Preferences
Undo Preferences Undo Preferences
Undo Limit Limit to X actions Limit the number of actions that can be undone to X actions. Unlimited Undo Don't limit the number of actions that can be undone. Keep Undo History After Save Always Always keep undo history after a file is saved. When dealing with large amounts of undo data this option may fill up all memory and cause a severe degradation of system performance. What fits in main memory Only keep the part of the history that fits in main memory (RAM). Never Never keep undo history after a file is saved.
Session Preferences
Session Preferences Session Preferences
Load previous session on startup Whether the previous session (the state of Bless at the time of the last quit) should be loaded on startup. The state includes all open files, the focused tab, the focused area in each file, the cursor position in each file and the window geometry. Ask before loading session Ask before loading session on startup. Remember cursor position Whether &app; should remember and restore the position of the cursor in each of the loaded files when loading the previous session. Remember window geometry Whether &app; should remember and restore the window size when loading the previous session.
Layout Files The way &app; presents the data is highly customizable. The configuration is done through layout description files. Currently there is no way to graphically edit the layouts but one is planned for a later version.
Selecting a layout &app; searches for layout description files in the $XDG_CONFIG_HOME/bless/layouts directory (usually $HOME/.config/bless/layouts). You can preview and select the available layouts with the layout selection dialog, which can be accessed by using View Layouts .
Creating Layout Files Layout description files are XML files ending with the .layout suffix. They consist of the <layout> tag which contains a series of <area> tags that describe each area in the layout. The <area> tag takes one attribute, type, which defines the type of the area. The valid values for type are: Type Description hexadecimal Displays the data in hexadecimal format. decimal Displays the data in decimal format. octal Displays the data in octal format. binary Displays the data in binary format. ascii Displays the data in ascii format. offset Displays the data offset. separator A vertical line that visually separates areas. For example, the following simple layout file: <layout> <area type="offset"></area> <area type="hexadecimal"></area> <area type="offset"></area> <area type="separator"></area> <area type="ascii"></area> </layout> produces the standard offset-hex-ascii view with default colors:
Standard offset-hex-ascii view Standard offset-hex-ascii view
Each area may include additional options about how to display the data. Some options are available to all areas whereas others are area-specific. The options that aren't explicitly defined assume their default values. Also if an option is specified for an area that doesn't support it, the option is just ignored. Option Values Description Areas display see below The fonts and colors that should be used for the display. all case upper|lower Whether to display hexadecimal values using lowercase or uppercase. offset, hexadecimal grouping #int The number of bytes that should be grouped together in each column. hexadecimal, decimal, octal, binary bpr #int The number of bytes on each row in the area (see below for more information) hexadecimal, decimal, octal, binary, ascii bytes #int The number of bytes which will be used to display offsets (default 4) offset
The bpr option The <bpr> (bytes per row) option sets the (maximum) number of bytes that each row in an area can have. If it is not specified, the number of bytes on each row changes dynamically in order to fill the whole available width. If it is specified in at least one area in the layout all the areas in the layout conform to the specified restriction. In case of a conflict, for example when two areas specify different bprs, the smallest value is used. Finally, if there is a conflict between bpr and grouping values, the highest value that conforms to the grouping and is below the bpr is used (eg if bpr=5 and grouping=2 the bytes per row will be 4).
The display option The <display> option is the most complicated of the lot and deserves additional explanation. Bless distinguishes between even and odd rows, and even and odd columns. You can choose how to color each of the above items thus creating a visual result tailored to your needs. This is achieved by using the <display> tag. Note that the first row and column are numbered as 0 and are therefore considered even. A <display> tag may contain a <font> tag which sets the font family and size to use for displaying data in the area (eg "Courier 10"). The font should be a monospaced font, otherwise the data in the area won't be displayed correctly. It is also advised to use same sized fonts in all the areas so that the data is correctly aligned. A <display> tag may also contain a <evenrow> and a <oddrow> tag which describe how the even and odd rows will look like. Each of the <evenrow> and <oddrow> tags may contain a <evencolumn>, an <oddcolumn>, a <selectedcolumn> and a <patternmatchcolumn> tag. The first two describe the appearance of the respective columns under normal conditions (no highlighting). The <selectedcolumn> tag describes the appearance of selected bytes and the <patternmatchcolumn> tag the appearance of the highlighted bytes that match the selected bytes (see ). The description for all the above is accomplished by using the <foreground> and <background> tags which specify the foreground and background colors to use. The colors can be specified either by name (eg dark blue) or by an RGB triad (eg #ff004e).
Display tag hierarchy Display tag hierarchy
An example: <layout> <area type="offset"> <display> <evenrow> <evencolumn> <foreground>dark red</foreground> </evencolumn> </evenrow> <oddrow> <evencolumn> <foreground>dark red</foreground> </evencolumn> </oddrow> </display> </area> <area type="separator"> <display> <evenrow> <evencolumn> <foreground>dark green</foreground> <background>white</background> </evencolumn> </evenrow> </display> </area> <area type="hexadecimal"> <grouping>2</grouping> <case>upper</case> <display> <evenrow> <selectedcolumn> <foreground>white</foreground> <background>#8faec8</background> </selectedcolumn> </evenrow> <oddrow> <evencolumn> <background>#eeeeee</background> </evencolumn> <oddcolumn> <background>#eeeeee</background> </oddcolumn> <selectedcolumn> <foreground>white</foreground> <background>#7b96ac</background> </selectedcolumn> </oddrow> </display> </area> <area type="separator"> <display> <evenrow> <evencolumn> <foreground>dark green</foreground> <background>white</background> </evencolumn> </evenrow> </display> </area> <area type="decimal"> </area> <area type="separator"> <display> <evenrow> <evencolumn> <foreground>dark green</foreground> <background>white</background> </evencolumn> </evenrow> </display> </area> <area type="binary"> </area> </layout> The result is:
Example layout Example layout screenshot
Not all font options are used in all areas. The hexadecimal, decimal, octal and binary areas use all options. The ascii, offset and separator areas do not use the <oddcolumn> tag. The */evencolumn/background colors are considered the primary background colors for their respective row. They are used to paint all parts of the row that are not otherwise painted (eg space between columns). The evenrow/evencolumn/background color is also considered the main background color of the area and is used to paint the unused parts of the area.
Extending with plugins As of version 0.5.0 &app; can be extended by using plugins. Internally &app; uses plugins for almost all of its GUI. Currently the parts that can be extended by plugins are: The GUI The areas displayed inside the Data Views Export builders See the developer documentation for more information on how to write plugins (TODO).
Frequently Asked Questions Philosophical Questions Why did you start Bless? Aren't there enough hex editors? There aren't enough free (as in speech) graphical hex editors. The two main ones are khexedit and ghex. Khexedit hasn't been updated in years and ghex is moving very slowly. So, why didn't you contribute to one of the existing projects? I wanted to try out the mono/Gtk# combination for graphical applications and none such project existed. What kind of name is Bless? It is a wordplay on the word hex. Hex also means curse and a bless(ing) is the opposite of a curse. Technical Questions How can I get the latest source of Bless? Bless now uses Git as its version control system. After you install Git on your system use the following command to get the latest version of Bless into the bless directory (this might take some time): git clone https://github.com/afrantzis/bless If you already downloaded a previous version (using the above command, not source tarballs) and want to update to the latest version use: git pull from within the directory that contains the previous version. I don't like the way Bless displays data. Can I change it? Yes! Bless is highly customizable. See I am trying to save a large file (under the same name) but while saving Bless complains that there is no space left! I was sure I had enough space! What's going on? To be able to save a file under the same name (File->Save command) you need to have (temporarily) enough disk space to hold both the original and the new file. This happens because the new file is created in a temporary file directory (eg /tmp see ) and then moved to its proper position. For example if you have a 20MB file and edit it so that it becomes 21MB and the new file is supposed to be saved in the same storage device as /tmp, you need to have 20+21=41MB free space in that storage device to be able to save it. After a successful save, the original file is deleted, in this case freeing 20MB.Although this can be a problem (when there is not enough disk space), it can also be seen as a safety measure in case something goes wrong when saving. A notable exception to the above is when the size of the file to be saved has not been changed. In that case the file is saved in-place. The data in the data areas isn't displayed correctly! What is wrong? On some systems the data in the data areas are garbled. This is an issue with the font subsystem. What happens is that the font subsystem reports to Bless a different font width than the one that is actually used on screen. This bug should be fixed in current versions of Pango. Anyway, the bug is now irrevelevant: since version 0.5.0 &app; uses a different way to measure the font width. Also, the temporary workaround with the FontWidthFix preference introduced in 0.4.1 is now disabled. If you are still experiencing such problems with versions >= 0.5.0 please file a bug report. Where does Bless keep its configuration files? See About &app; &app; was written by Alexandros Frantzis (alf82 at freemail dot gr). To find more information about &app;, please visit the Bless Web page. This program is distributed 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. A copy of this license can be found at this link, or in the file COPYING included with the source code of this program. bless-0.6.3/doc/user/C/legal.xml000066400000000000000000000071301374060072200163450ustar00rootroot00000000000000 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. bless-0.6.3/doc/user/meson.build000066400000000000000000000041611374060072200165200ustar00rootroot00000000000000gnome = import('gnome') help_sources = [ 'index.docbook', 'legal.xml', ] help_html = [ 'ch01.html', 'ch02.html', 'ch02s02.html', 'ch03.html', 'ch03s02.html', 'ch04.html', 'ch04s02.html', 'ch04s03.html', 'ch04s04.html', 'ch04s05.html', 'ch04s06.html', 'ch05.html', 'ch05s02.html', 'ch05s03.html', 'ch05s04.html', 'ch06.html', 'ch07.html', 'index.html', ] help_media = [ 'figures/bless_area_focus.png', 'figures/bless_bitwise_ops.png', 'figures/bless_display_tag.png', 'figures/bless_edit_mode.png', 'figures/bless_export_dialog.png', 'figures/bless_goto.png', 'figures/bless_layout_example1.png', 'figures/bless_layout_oha.png', 'figures/bless_number_base.png', 'figures/bless_preferences_general.png', 'figures/bless_preferences_session.png', 'figures/bless_preferences_undo.png', 'figures/bless_search_find.png', 'figures/bless_search_replace.png', 'figures/bless_select_range.png', 'figures/bless_start_window.png', 'figures/bless_tab_close.png', ] if get_option('html_user_doc') html_xsl = 'http://docbook.sourceforge.net/release/xsl/current/html/chunk.xsl' xsltproc = find_program('xsltproc', required: false) if xsltproc.found() cmd = run_command([xsltproc, '--nonet', html_xsl]) if cmd.returncode() != 0 error('No XSLT stylesheet found, cannot generating html documentation. You can disable with -Dhtml_user_doc=false') endif else error('No XSLT processor found, cannot generating html documentation. You can disable with -Dhtml_user_doc=false') endif custom_target( 'help-html', command: [xsltproc, '--nonet', '-o', '@OUTDIR@/', html_xsl, '@INPUT@'], input: files('C/index.docbook'), output: help_html, build_by_default: true, install: true, install_dir: join_paths(get_option('datadir'), 'help', 'C', meson.project_name()), ) endif gnome.yelp( meson.project_name(), sources: help_sources, media: help_media, symlink_media: true, ) bless-0.6.3/meson.build000066400000000000000000000006421374060072200147750ustar00rootroot00000000000000project( 'bless', 'cs', version: '0.6.3', meson_version: '>= 0.46', default_options: ['libdir=lib'], ) add_project_arguments('-d:ENABLE_UNIX_SPECIFIC', language: 'cs') gtk_sharp_2_dep = dependency('gtk-sharp-2.0') glib_sharp_2_dep = dependency('glib-sharp-2.0') subdir('src') subdir('data') if get_option('tests') subdir('tests') endif if get_option('user_doc') subdir('doc/user') endif bless-0.6.3/meson_options.txt000066400000000000000000000010111374060072200162570ustar00rootroot00000000000000option('user_doc', type: 'boolean', value: true, description: 'Build and install docbook user documentation') option('html_user_doc', type: 'boolean', value: true, description: 'Build and install HTML user documentation (requires xsltproc and stylesheets)') option('tests', type: 'boolean', value: true, description: 'Build tests (requires nunit)') option('run_tests', type: 'boolean', value: true, description: 'Whether to run tests (requires nunit-console)') bless-0.6.3/po/000077500000000000000000000000001374060072200132475ustar00rootroot00000000000000bless-0.6.3/po/LINGUAS000066400000000000000000000000001374060072200142620ustar00rootroot00000000000000bless-0.6.3/po/Makevars000066400000000000000000000034031374060072200147430ustar00rootroot00000000000000# Makefile variables for PO directory in any package using GNU gettext. # Usually the message domain is the same as the package name. DOMAIN = $(PACKAGE) # These two variables depend on the location of this directory. subdir = po top_builddir = .. # These options get passed to xgettext. XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ # This is the copyright holder that gets inserted into the header of the # $(DOMAIN).pot file. Set this to the copyright holder of the surrounding # package. (Note that the msgstr strings, extracted from the package's # sources, belong to the copyright holder of the package.) Translators are # expected to transfer the copyright for their translations to this person # or entity, or to disclaim their copyright. The empty string stands for # the public domain; in this case the translators are expected to disclaim # their copyright. COPYRIGHT_HOLDER = Alexandros Frantzis # This is the email address or URL to which the translators shall report # bugs in the untranslated strings: # - Strings which are not entire sentences, see the maintainer guidelines # in the GNU gettext documentation, section 'Preparing Strings'. # - Strings which use unclear terms or require additional context to be # understood. # - Strings which make invalid assumptions about notation of date, time or # money. # - Pluralisation problems. # - Incorrect English spelling. # - Incorrect formatting. # It can be your email address, or a mailing list address where translators # can write to without being subscribed, or the URL of a web page through # which the translators can contact you. MSGID_BUGS_ADDRESS = # This is the list of locale categories, beyond LC_MESSAGES, for which the # message catalogs shall be used. It is usually empty. EXTRA_LOCALE_CATEGORIES = bless-0.6.3/po/POTFILES.in000066400000000000000000000023041374060072200150230ustar00rootroot00000000000000# List of source files which contain translatable strings. data/ui/BitwiseOperationsPlugin.ui data/ui/ConversionTablePlugin.ui data/ui/ExportDialog.ui data/ui/FindReplacePlugin.ui data/ui/GotoOffsetPlugin.ui data/ui/LayoutSelectionDialog.ui data/ui/MainWindow.ui data/ui/PreferencesDialog.ui data/ui/ProgressDialog.ui data/ui/ProgressDisplayPlugin.ui data/ui/SelectRangePlugin.ui src/buffers/SaveAsOperation.cs src/buffers/SaveOperation.cs src/gui/FileChangedBar.cs src/gui/FileService.cs src/gui/MainWindow.cs src/gui/dialogs/AboutDialog.cs src/gui/dialogs/ExportDialog.cs src/gui/dialogs/FileOverwriteAlert.cs src/gui/dialogs/LayoutSelectionDialog.cs src/gui/dialogs/PreferencesDialog.cs src/gui/dialogs/RevertConfirmationAlert.cs src/gui/dialogs/SaveConfirmationAlert.cs src/gui/dialogs/SaveConfirmationMultiAlert.cs src/gui/plugins/ConversionTablePlugin.cs src/gui/plugins/CopyOffsetPlugin.cs src/gui/plugins/FileExportPlugin.cs src/gui/plugins/FileOperationsPlugin.cs src/gui/plugins/FindReplacePlugin.cs src/gui/plugins/GotoOffsetPlugin.cs src/gui/plugins/HelpOperationsPlugin.cs src/gui/plugins/InfobarPlugin.cs src/gui/plugins/SelectLayoutPlugin.cs src/gui/plugins/SelectRangePlugin.cs src/util/BaseConverter.cs bless-0.6.3/src/000077500000000000000000000000001374060072200134205ustar00rootroot00000000000000bless-0.6.3/src/bless-bin.in000077500000000000000000000000641374060072200156310ustar00rootroot00000000000000#!/bin/sh mono "@blessassemblydir@/bless.exe" "$@" bless-0.6.3/src/buffers/000077500000000000000000000000001374060072200150545ustar00rootroot00000000000000bless-0.6.3/src/buffers/ByteBuffer.cs000066400000000000000000000570121374060072200174450ustar00rootroot00000000000000// created on 6/6/2004 at 10:46 AM /* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System.Collections; using System; using System.IO; using System.Threading; using Bless.Util; using Bless.Tools; using Mono.Unix; namespace Bless.Buffers { /// /// A buffer for holding bytes in a versatile manner. /// It supports undo-redo and can easily handle large files. /// Editing is also very cheap. /// public class ByteBuffer : BaseBuffer { ///The file buffer associated with the ByteBuffer internal FileBuffer fileBuf; ///The collection of segments that comprise the ByteBuffer internal SegmentCollection segCol; ///Double ended queues to hold undo/redo actions Deque undoDeque; Deque redoDeque; ///The last action before a Save was made ByteBufferAction SaveCheckpoint; ///Watches the file for external changes (outside Bless) FileSystemWatcher fsw; int maxUndoActions; bool changedBeyondUndo; string tempDir; // automatic file naming string autoFilename; static int autoNum = 1; internal long size; // chaining related bool actionChaining; bool actionChainingFirst; MultiAction multiAction; /// /// Object to use for synchronized access to the ByteBuffer /// readonly public object LockObj = new object(); // buffer permissions bool readAllowed; bool modifyAllowed; bool fileOperationsAllowed; bool emitEvents; public delegate void ChangedHandler(ByteBuffer bb); ///Emitted when buffer changes public event ChangedHandler Changed; ///Emitted when file changes (outside DataView) public event ChangedHandler FileChanged; ///Emitted when buffer permissions change public event ChangedHandler PermissionsChanged; public void EmitChanged() { if (emitEvents && Changed != null) { Changed(this); } } public void EmitFileChanged() { if (emitEvents && FileChanged != null) { FileChanged(this); } } public void EmitPermissionsChanged() { if (emitEvents && PermissionsChanged != null) { PermissionsChanged(this); } } // related to asynchronous save model AsyncCallback userSaveAsyncCallback; AutoResetEvent saveFinishedEvent; bool useGLibIdle; public ByteBuffer() { segCol = new SegmentCollection(); undoDeque = new Deque(); redoDeque = new Deque(); size = 0; SaveCheckpoint = null; // name the buffer automatically autoFilename = Catalog.GetString("Untitled") + " " + ByteBuffer.autoNum; ByteBuffer.autoNum++; // set default permissions readAllowed = true; fileOperationsAllowed = true; modifyAllowed = true; saveFinishedEvent = new AutoResetEvent(false); useGLibIdle = false; emitEvents = true; maxUndoActions = -1; // unlimited undo tempDir = Path.GetTempPath(); } ///Create a ByteBuffer loaded with a file static public ByteBuffer FromFile(string filename) { ByteBuffer bb = new ByteBuffer(); bb.LoadWithFile(filename); // fix automatic file naming ByteBuffer.autoNum--; return bb; } ///Create a ByteBuffer with a dummy-name public ByteBuffer(string filename): this() { this.autoFilename = filename; // fix automatic file naming ByteBuffer.autoNum--; } ///Regard all following actions as a single one public void BeginActionChaining() { actionChaining = true; actionChainingFirst = true; multiAction = new MultiAction(); emitEvents = false; } ///Stop regarding actions as a single one public void EndActionChaining() { actionChaining = false; actionChainingFirst = false; emitEvents = true; EmitChanged(); } ///Handle actions as a single one bool HandleChaining(ByteBufferAction action) { if (!actionChaining) return false; // add the multiAction to the undo deque if (actionChainingFirst) { AddUndoAction(multiAction); actionChainingFirst = false; } multiAction.Add(action); return true; } /// /// Add an action to the undo deque, taking into /// account maximum undo action restrictions /// void AddUndoAction(ByteBufferAction action) { if (maxUndoActions!=-1) while (undoDeque.Count >= maxUndoActions) { undoDeque.RemoveEnd(); changedBeyondUndo = true; } undoDeque.AddFront(action); } void RedoDequeDispose() { redoDeque.Clear(); } ///Append bytes at the end of the buffer public override void Append(byte[] data, long index, long length) { lock (LockObj) { if (!modifyAllowed) return; if (!IsResizable) return; AppendAction aa = new AppendAction(data, index, length, this); aa.Do(); // if action isn't handled as chained (ActionChaining==false) // handle it manually if (!HandleChaining(aa)) { AddUndoAction(aa); RedoDequeDispose(); } EmitChanged(); } } ///Insert bytes into the buffer public override void Insert(long pos, byte[] data, long index, long length) { lock (LockObj) { if (!modifyAllowed) return; if (!IsResizable) return; if (pos == size) { Append(data, index, length); return; } InsertAction ia = new InsertAction(pos, data, index, length, this); ia.Do(); // if action isn't handled as chained (ActionChaining == false) // handle it manually if (!HandleChaining(ia)) { AddUndoAction(ia); RedoDequeDispose(); } EmitChanged(); } } ///Delete bytes from the buffer public void Delete(long pos1, long pos2) { lock (LockObj) { if (!modifyAllowed) return; if (!IsResizable) return; DeleteAction da = new DeleteAction(pos1, pos2, this); da.Do(); // if action isn't handled as chained (ActionChaining == false) // handle it manually if (!HandleChaining(da)) { AddUndoAction(da); RedoDequeDispose(); } EmitChanged(); } } ///Replace bytes in the buffer public void Replace(long pos1, long pos2, byte[] data, long index, long length) { lock (LockObj) { if (!modifyAllowed) return; // if the file isn't resizable allow replaces // only if they don't change the file length bool equalLength = (pos2 - pos1 + 1 == length); if (!IsResizable && !equalLength) return; ReplaceAction ra = new ReplaceAction(pos1, pos2, data, index, length, this); ra.Do(); // if action isn't handled as chained (ActionChaining == false) // handle it manually if (!HandleChaining(ra)) { AddUndoAction(ra); RedoDequeDispose(); } EmitChanged(); } } public void Replace(long pos1, long pos2, byte[] data) { Replace(pos1, pos2, data, 0, data.Length); } ///Undo the last action public void Undo() { lock (LockObj) { if (!modifyAllowed) return; // if there is an action to undo if (undoDeque.Count > 0) { ByteBufferAction action = undoDeque.RemoveFront(); action.Undo(); redoDeque.AddFront(action); EmitChanged(); } } } ///Redo the last undone action public void Redo() { lock (LockObj) { if (!modifyAllowed) return; // if there is an action to redo if (redoDeque.Count > 0) { ByteBufferAction action = redoDeque.RemoveFront(); action.Do(); AddUndoAction(action); EmitChanged(); } } } /// /// Save the buffer as a file, using an asynchronous model /// public IAsyncResult BeginSaveAs(string filename, ProgressCallback progressCallback, AsyncCallback ac) { lock (LockObj) { if (!fileOperationsAllowed) return null; saveFinishedEvent.Reset(); userSaveAsyncCallback = ac; SaveAsOperation so = new SaveAsOperation(this, filename, progressCallback, SaveAsAsyncCallback, useGLibIdle); // don't allow messing up with the buffer // while we are saving // ...ReadAllowed is set in SaveOperation // this.ReadAllowed = false; this.ModifyAllowed = false; this.FileOperationsAllowed = false; this.EmitEvents = false; if (fsw != null) fsw.EnableRaisingEvents = false; // start save thread Thread saveThread = new Thread(so.OperationThread); saveThread.IsBackground = true; saveThread.Start(); return new ThreadedAsyncResult(so, saveFinishedEvent, false); } } /// /// Called when an asynchronous Save As operation finishes /// void SaveAsAsyncCallback(IAsyncResult ar) { lock (LockObj) { SaveAsOperation so = (SaveAsOperation)ar.AsyncState; // re-allow buffer usage this.FileOperationsAllowed = true; // make sure Save As went smoothly before doing anything if (so.Result==SaveAsOperation.OperationResult.Finished) { // make sure data in undo redo are stored safely // because we are going to close the file MakePrivateCopyOfUndoRedo(); CloseFile(); LoadWithFile(so.SavePath); if (undoDeque.Count > 0) SaveCheckpoint = undoDeque.PeekFront(); else SaveCheckpoint = null; changedBeyondUndo = false; } else { // if cancelled or caught an exception // delete the file only if we have altered it if (so.StageReached != SaveAsOperation.SaveAsStage.BeforeCreate) { try { System.IO.File.Delete(so.SavePath); } catch (Exception e) { System.Console.WriteLine(e.Message); } } } // re-allow buffer usage this.ReadAllowed = true; this.ModifyAllowed = true; this.EmitEvents = true; if (fsw != null) fsw.EnableRaisingEvents = true; // notify the world about the changes EmitPermissionsChanged(); EmitChanged(); // if user provided a callback, call it now if (userSaveAsyncCallback != null) userSaveAsyncCallback(ar); // notify that Save As has finished saveFinishedEvent.Set(); } } /// /// Save the buffer under the same filename, using an asynchronous model /// public IAsyncResult BeginSave(ProgressCallback progressCallback, AsyncCallback ac) { lock (LockObj) { if (!fileOperationsAllowed) return null; saveFinishedEvent.Reset(); userSaveAsyncCallback = ac; Thread saveThread = null; ThreadedAsyncResult tar = null; // decide whether to save in place or normally if (!fileBuf.IsResizable || this.Size == fileBuf.Size) { SaveInPlaceOperation sipo = new SaveInPlaceOperation(this, progressCallback, SaveInPlaceAsyncCallback, useGLibIdle); saveThread = new Thread(sipo.OperationThread); tar = new ThreadedAsyncResult(sipo, saveFinishedEvent, false); } else { SaveOperation so = new SaveOperation(this, TempFile.CreateName(tempDir), progressCallback, SaveAsyncCallback, useGLibIdle); saveThread = new Thread(so.OperationThread); tar = new ThreadedAsyncResult(so, saveFinishedEvent, false); } // don't allow messing up with the buffer // while we are saving // ...ReadAllowed is set in SaveOperation //this.ReadAllowed=false; this.ModifyAllowed = false; this.FileOperationsAllowed = false; this.EmitEvents = false; fsw.EnableRaisingEvents = false; // start save thread saveThread.IsBackground = true; saveThread.Start(); return tar; } } /// /// Called when an asynchronous save operation finishes /// void SaveAsyncCallback(IAsyncResult ar) { lock (LockObj) { SaveOperation so = (SaveOperation)ar.AsyncState; if (so.Result == SaveOperation.OperationResult.Finished) { // save went ok // No need to call CloseFile() MakePrivateCopyOfUndoRedo() // because it has already been called in SaveOperation LoadWithFile(so.SavePath); if (undoDeque.Count > 0) SaveCheckpoint = undoDeque.PeekFront(); else SaveCheckpoint = null; changedBeyondUndo = false; } else if (so.Result == SaveOperation.OperationResult.Cancelled) { // save cancelled if (so.StageReached == SaveOperation.SaveStage.BeforeSaveAs) { System.IO.File.Delete(so.TempPath); } else if (so.StageReached == SaveOperation.SaveStage.BeforeDelete) { System.IO.File.Delete(so.TempPath); fileBuf.Load(so.SavePath); } else if (so.StageReached == SaveOperation.SaveStage.BeforeMove) { // cancel has no effect during move. // mark operation as successful so.Result = SaveOperation.OperationResult.Finished; LoadWithFile(so.SavePath); if (undoDeque.Count > 0) SaveCheckpoint = undoDeque.PeekFront(); else SaveCheckpoint = null; } } else if (so.Result == SaveOperation.OperationResult.CaughtException) { if (so.StageReached == SaveOperation.SaveStage.BeforeSaveAs) { System.IO.File.Delete(so.TempPath); } else if (so.StageReached == SaveOperation.SaveStage.BeforeDelete) { System.IO.File.Delete(so.TempPath); fileBuf.Load(so.SavePath); // make sure FSW is valid (it is probably not // because bb.CloseFile has been called in SaveOperation) SetupFSW(); } else if (so.StageReached == SaveOperation.SaveStage.BeforeMove) { // TO-DO: better handling? fileBuf.Load(so.SavePath); } } // re-allow buffer usage this.ReadAllowed = true; this.ModifyAllowed = true; this.FileOperationsAllowed = true; this.EmitEvents = true; fsw.EnableRaisingEvents = true; // notify the world about the changes EmitPermissionsChanged(); EmitChanged(); // if user provided a callback, call it now if (userSaveAsyncCallback != null) userSaveAsyncCallback(ar); // notify that Save has finished saveFinishedEvent.Set(); } } /// /// Called when an asynchronous in-place save operation finishes /// void SaveInPlaceAsyncCallback(IAsyncResult ar) { lock (LockObj) { SaveInPlaceOperation sipo = (SaveInPlaceOperation)ar.AsyncState; if (sipo.Result == ThreadedAsyncOperation.OperationResult.Finished) { // save went ok LoadWithFile(sipo.SavePath); if (undoDeque.Count > 0) SaveCheckpoint = undoDeque.PeekFront(); else SaveCheckpoint = null; changedBeyondUndo = false; } else if (sipo.Result == ThreadedAsyncOperation.OperationResult.Cancelled) { // save cancelled } else if (sipo.Result == ThreadedAsyncOperation.OperationResult.CaughtException) { } // re-allow buffer usage this.ReadAllowed = true; this.ModifyAllowed = true; this.FileOperationsAllowed = true; this.EmitEvents = true; fsw.EnableRaisingEvents = true; // notify the world about the changes EmitPermissionsChanged(); EmitChanged(); // if user provided a callback, call it now if (userSaveAsyncCallback != null) userSaveAsyncCallback(ar); // notify that Save has finished saveFinishedEvent.Set(); } } /// /// Revert ByteBuffer to the last saved state /// public void Revert() { lock (LockObj) { if (!modifyAllowed) return; if (this.HasFile) { // reload file string filename = fileBuf.Filename; if (!File.Exists(filename)) throw new FileNotFoundException(filename); fileBuf.Close(); undoDeque.Clear(); redoDeque.Clear(); LoadWithFile(filename); SaveCheckpoint = null; changedBeyondUndo = false; // emit bytebuffer changed event EmitChanged(); } } } /// /// Returns in a byte array the data contained in /// the specified range in the buffer. /// public byte[] RangeToByteArray(IRange range) { if (range.Size==0) return null; byte[] rangeData=new byte[range.Size]; long i=0; while (i < range.Size) { rangeData[i]=this[range.Start+i]; i++; } return rangeData; } /// /// Returns as a SegmentCollection the data contained in /// the specified range in the buffer. /// public SegmentCollection RangeToSegmentCollection(Util.Range range) { if (range.Size == 0) return null; return segCol.GetRange(range.Start, range.End); } /// /// Sets the file buffer and resets the segment collection /// private void LoadWithFile(string filename) { if (fileBuf == null) fileBuf = new FileBuffer(filename, 0xffff); // 64KB buffer else { fileBuf.Load(filename); } Segment s = new Segment(fileBuf, 0, fileBuf.Size-1); segCol = new SegmentCollection(); segCol.Append(s); size = fileBuf.Size; SetupFSW(); } internal void MakePrivateCopyOfUndoRedo() { // Data in the actions may reference a file buffer that // can become invalid (eg after saving a file) // Copy the data to private in-memory buffers to avoid data corruption // and crashes... // if (Preferences.Instance["Undo.KeepAfterSave"] == "Never") { undoDeque.Clear(); redoDeque.Clear(); return; } if (Preferences.Instance["Undo.KeepAfterSave"] == "Always") { foreach(ByteBufferAction action in undoDeque) action.MakePrivateCopyOfData(); foreach(ByteBufferAction action in redoDeque) action.MakePrivateCopyOfData(); return; } // if Preferences.Instance["Undo.KeepAfterSave"] == "Memory" // drop the undo and redo actions that don't fit into memory (and all actions // after them in the Deques). Deque newUndoDeque = new Deque(); Deque newRedoDeque = new Deque(); foreach(ByteBufferAction action in undoDeque) { long freeMem = long.MaxValue; try { freeMem = Portable.GetAvailableMemory(); } catch(NotImplementedException) {} if (freeMem < action.GetPrivateCopySize()) break; action.MakePrivateCopyOfData(); newUndoDeque.AddEnd(action); } foreach(ByteBufferAction action in redoDeque) { long freeMem = long.MaxValue; try { freeMem = Portable.GetAvailableMemory(); } catch(NotImplementedException) {} if (freeMem < action.GetPrivateCopySize()) break; action.MakePrivateCopyOfData(); newRedoDeque.AddEnd(action); } undoDeque.Clear(); redoDeque.Clear(); undoDeque = newUndoDeque; redoDeque = newRedoDeque; } private void SetupFSW() { // monitor the file for changes if (fsw != null) { fsw.Dispose(); fsw = null; } fsw = new FileSystemWatcher(); fsw.Path = Path.GetDirectoryName(fileBuf.Filename); fsw.Filter = Path.GetFileName(fileBuf.Filename); // Currently we only properly support file content changes fsw.NotifyFilter = NotifyFilters.LastWrite; fsw.Changed += new FileSystemEventHandler(OnFileChanged); fsw.EnableRaisingEvents = true; } private void OnFileChanged(object source, FileSystemEventArgs e) { EmitFileChanged(); } public override byte this[long index] { set { } get { lock (LockObj) { if (!readAllowed) { return 0;} long map; Util.List.Node node; Segment seg = segCol.FindSegment(index, out map, out node); //Console.WriteLine("Searching index {0} at {1}:{2}", index, map, seg); if (seg == null) throw new IndexOutOfRangeException(string.Format("ByteBuffer[{0}]",index)); else { try { return seg.Buffer[seg.Start+index-map]; } catch(IndexOutOfRangeException) { Console.WriteLine("Problem at index {0} at {1}:{2}", index, map, seg); throw; } } } } } /// /// Close the file associated with the ByteBuffer /// public void CloseFile() { lock (LockObj) { // close the file buffer and dispose the file watcher if (fileBuf != null && fileOperationsAllowed) { fileBuf.Close(); fsw.Dispose(); fsw = null; segCol = null; // buffer is in an unreadable state... this.ReadAllowed = false; } } } public override long Size { get { return size;} } public bool HasFile { get { return fileBuf != null; } } public string Filename { get { if (fileBuf != null) return fileBuf.Filename; else return this.autoFilename; } } public bool HasChanged { get { if (undoDeque.Count > 0) return (changedBeyondUndo || SaveCheckpoint != undoDeque.PeekFront()); else return (changedBeyondUndo || SaveCheckpoint != null); } } public bool CanUndo { get { return (undoDeque.Count > 0); } } public bool CanRedo { get { return (redoDeque.Count > 0); } } public bool ActionChaining { get { return actionChaining; } } // Whether the ByteBuffer will emit events // (eg Changed event) public bool EmitEvents { get { return emitEvents; } set { emitEvents = value; } } // whether buffer can be safely read // by user eg to display data in a DataView. // if false reading from the buffer just returns zeroes public bool ReadAllowed { get { return readAllowed; } set { readAllowed = value; EmitPermissionsChanged(); } } // Whether buffer can be modified. // If it is false, all buffer actions // that can modify the buffer are // rendered ineffective. public bool ModifyAllowed { get { return modifyAllowed;} set { modifyAllowed = value; EmitPermissionsChanged(); } } // Whether buffer can be saved, closed etc // If it is false, all save and close operations // are ignored. public bool FileOperationsAllowed { get { return fileOperationsAllowed;} set { fileOperationsAllowed = value; EmitPermissionsChanged(); } } // Whether buffer can be resized (read-only property) public bool IsResizable { get { if (fileBuf != null) return fileBuf.IsResizable; else return true; } } // Use the GLib Idle handler for progress reporting. // Mandatory if progress reporting involves Gtk+ widgets. public bool UseGLibIdle { get { return useGLibIdle; } set { useGLibIdle = value; } } // The maximum number of actions the Buffer // will be able to undo public int MaxUndoActions { get { return maxUndoActions; } set { maxUndoActions = value; if (maxUndoActions != -1) { // if we are going to remove undo actions, // mark that we won't be able to get back to // the original buffer state if (undoDeque.Count > maxUndoActions) changedBeyondUndo = true; // clear all undo actions beyond the limit while (undoDeque.Count > maxUndoActions) { undoDeque.RemoveEnd(); } } } } /// /// The directory where temporary files are stored /// public string TempDir { get { return tempDir; } set { tempDir = (value == "") ? Path.GetTempPath() : value; } } /// /// The range of the buffer as a Util.Range /// public Util.Range Range { get { Util.Range range = new Util.Range(); if (size > 0) { range.Start = 0; range.End = size - 1; } return range; } } internal void Display(string s) { Console.Write(s); segCol.List.Display(); } } } // end namespace bless-0.6.3/src/buffers/ByteBufferAction.cs000066400000000000000000000124741374060072200206060ustar00rootroot00000000000000// created on 2/13/2005 at 7:02 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.Collections.Generic; namespace Bless.Buffers { ///Abstract class for ByteBuffer actions abstract class ByteBufferAction { abstract public void Do(); abstract public void Undo(); virtual public void MakePrivateCopyOfData() { } virtual public long GetPrivateCopySize() { return 0; } } ///Action for appending at the end of a ByteBuffer class AppendAction: ByteBufferAction { Segment seg; ByteBuffer byteBuf; public AppendAction(byte[] d, long index, long length, ByteBuffer bb) { byteBuf = bb; // if there is no data to append // don't create a segment if (d.Length == 0) seg = null; else { SimpleBuffer cb = new SimpleBuffer(); seg = new Segment(cb, cb.Size, cb.Size + length - 1); cb.Append(d, index, length); } } public override void Do() { if (seg == null) return; // use copy of segment seg to protect it from alterations byteBuf.segCol.Append(new Segment(seg.Buffer, seg.Start, seg.End)); byteBuf.size += seg.Size; } public override void Undo() { if (seg == null) return; byteBuf.size -= seg.Size; byteBuf.segCol.DeleteRange(byteBuf.size, byteBuf.size + seg.Size - 1); } } ///Action for inserting in a ByteBuffer class InsertAction: ByteBufferAction { Segment seg; long pos; ByteBuffer byteBuf; public InsertAction(long p, byte[] d, long index, long length, ByteBuffer bb) { byteBuf = bb; pos = p; // if there is no data to insert // don't create a segment if (length == 0) seg = null; else { SimpleBuffer cb = new SimpleBuffer(); seg = new Segment(cb, cb.Size, cb.Size + length - 1); cb.Append(d, index, length); } } public override void Do() { if (seg == null) return; SegmentCollection tmp = new SegmentCollection(); // use copy of segment seg to protect it from alterations tmp.Append(new Segment(seg.Buffer, seg.Start, seg.End)); byteBuf.segCol.Insert(tmp, pos); byteBuf.size += seg.Size; } public override void Undo() { if (seg == null) return; byteBuf.segCol.DeleteRange(pos, pos + seg.Size - 1); byteBuf.size -= seg.Size; } } ///Action for deleting from a ByteBuffer class DeleteAction: ByteBufferAction { SegmentCollection del; long pos1, pos2; ByteBuffer byteBuf; public DeleteAction(long p1, long p2, ByteBuffer bb) { byteBuf = bb; pos1 = p1; pos2 = p2; } public override void Do() { del = byteBuf.segCol.DeleteRange(pos1, pos2); byteBuf.size -= pos2 - pos1 + 1; } public override void Undo() { byteBuf.segCol.Insert(del, pos1); byteBuf.size += pos2 - pos1 + 1; } public override void MakePrivateCopyOfData() { foreach(Segment seg in del.List) { if (seg.Buffer.GetType() == typeof(FileBuffer)) { seg.MakePrivateCopyOfData(); } } } public override long GetPrivateCopySize() { long size = 0; foreach(Segment seg in del.List) { if (seg.Buffer.GetType() == typeof(FileBuffer)) { size += seg.Size; } } return size; } } ///Convenience action for replacing data in ByteBuffer class ReplaceAction: ByteBufferAction { DeleteAction del; InsertAction ins; public ReplaceAction(long p1, long p2, byte[] d, long index, long length, ByteBuffer bb) { del = new DeleteAction(p1, p2, bb); ins = new InsertAction(p1, d, index, length, bb); } public override void Do() { del.Do(); ins.Do(); } public override void Undo() { ins.Undo(); del.Undo(); } public override void MakePrivateCopyOfData() { del.MakePrivateCopyOfData(); } public override long GetPrivateCopySize() { return del.GetPrivateCopySize(); } } ///Container fo many related ByteBufferActions class MultiAction: ByteBufferAction { List list; public MultiAction() { list = new List(); } public void Add(ByteBufferAction action) { list.Add(action); } public override void Do() { // do the actions in normal order for(int i = 0; i < list.Count; i++) list[i].Do(); } public override void Undo() { // undo the actions in reverse order for(int i = list.Count - 1; i >= 0; i--) list[i].Undo(); } public override void MakePrivateCopyOfData() { foreach(ByteBufferAction a in list) { a.MakePrivateCopyOfData(); } } public override long GetPrivateCopySize() { long size = 0; foreach(ByteBufferAction a in list) { size += a.GetPrivateCopySize(); } return size; } } } // end namespace bless-0.6.3/src/buffers/FileBuffer.cs000066400000000000000000000112471374060072200174210ustar00rootroot00000000000000// created on 6/5/2004 at 5:04 PM /* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System.IO; using System; using Mono.Unix; using System.Runtime.InteropServices; namespace Bless.Buffers { /// /// A buffer that allows access to a file by using a moving window /// public class FileBuffer: BaseBuffer { [DllImport ("libc", SetLastError=true)] static extern int ioctl (int fd, uint request, ref long size); const uint BLKGETSIZE64 = 0x80041272; ///The offset in the file of the start of the buffer window long winOffset; ///The number of bytes in the window that contain valid file data int winOccupied; ///The data window byte[] window; ///Whether the file object is resizable bool isResizable; BinaryReader reader; long FileLength; const int default_size=4096; public FileBuffer(string fn): this(fn,default_size) { } public FileBuffer(string fn, int size) { window = new byte[size]; Load(fn); } /// /// Whether offset pos is contained in the current window /// private bool InWindow(long pos) { return (pos >= winOffset && pos < winOffset + winOccupied); } /// /// Read data from the buffer /// public override long Read(byte[] ba, long index, long pos, long len) { // bounds checking if (pos >= FileLength || pos<0) return 0; if (pos + len > FileLength) len = FileLength-pos+1; reader.BaseStream.Seek(pos, SeekOrigin.Begin); // FIXME: The casts are dangerous but .NET doesn't have // an Int64 version of Read()! reader.Read(ba, (int)index, (int)len); // seek back to previous position //reader.BaseStream.Seek(winOffset, SeekOrigin.Begin); return len; } public override byte this[long index] { set { /* read only buffer */ } get { // if the offset we are trying to read is not in the // current window, load the window with data from the file // so that the offset is in the middle of the window if (!InWindow(index)) { if (index >= FileLength) { throw new IndexOutOfRangeException(); } winOffset = index - window.Length / 2; if (winOffset < 0) winOffset = 0; reader.BaseStream.Seek(winOffset, SeekOrigin.Begin); winOccupied = reader.Read(window, 0, window.Length); } return window[index-winOffset]; } } public override long Size { get { return FileLength; } } /// /// Load the buffer with a file /// public void Load(string filename) { if (reader != null) reader.Close(); #if ENABLE_UNIX_SPECIFIC UnixFileInfo fsInfo = new UnixFileInfo(filename); if (!fsInfo.Exists) throw new FileNotFoundException(fsInfo.FullName); // get the size of the file or device if (fsInfo.IsRegularFile) { FileLength = fsInfo.Length; isResizable = true; } else if (fsInfo.IsBlockDevice) { UnixStream unixStream = fsInfo.OpenRead(); ioctl(unixStream.Handle, BLKGETSIZE64, ref FileLength); unixStream.Close(); isResizable = false; } else throw new NotSupportedException("File object isn't a regular or block device."); #endif Stream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); if (stream.CanSeek == false) throw new NotSupportedException("File object doesn't support seeking."); #if !ENABLE_UNIX_SPECIFIC FileLength = stream.Seek(0, SeekOrigin.End); stream.Seek(0, SeekOrigin.Begin); isResizable = false; #endif reader = new BinaryReader(stream); winOccupied = reader.Read(window, 0, window.Length); winOffset = 0; } public string Filename { get { if (reader != null) return (reader.BaseStream as FileStream).Name; else return null; } } public bool IsResizable { get { return isResizable; } } public void Close() { reader.Close(); reader = null; } } } // end namespace bless-0.6.3/src/buffers/IBuffer.cs000066400000000000000000000041701374060072200167270ustar00rootroot00000000000000// created on 6/4/2004 at 3:37 PM /* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; namespace Bless.Buffers { public interface IBuffer { void Insert(long pos, byte[] data, long index, long length); long Read(byte[] data, long index, long pos, long len); void Append(byte[] data, long index, long length); void InsertBuffer(long pos, IBuffer buf, long index, long length); void AppendBuffer(IBuffer buf, long index, long length); byte this[long index] { set; get; } long Size { get; } } public class BaseBuffer : IBuffer { public virtual void Insert(long pos, byte[] data, long index, long length) { throw new NotImplementedException(); } public virtual long Read(byte[] data, long index, long pos, long len) { throw new NotImplementedException(); } public virtual void Append(byte[] data, long index, long length) { throw new NotImplementedException(); } public virtual void InsertBuffer(long pos, IBuffer buf, long index, long length) { throw new NotImplementedException(); } public virtual void AppendBuffer(IBuffer buf, long index, long length) { throw new NotImplementedException(); } public virtual byte this[long index] { set { throw new NotImplementedException(); } get { throw new NotImplementedException(); } } public virtual long Size { get { throw new NotImplementedException(); } } } } bless-0.6.3/src/buffers/ISaveState.cs000066400000000000000000000023221374060072200174120ustar00rootroot00000000000000// created on 2/24/2008 at 5:02 PM /* * Copyright (c) 2008, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using Bless.Util; namespace Bless.Buffers { ///Holds information about the state of an asynchronous save operation public interface ISaveState { ThreadedAsyncOperation.OperationResult Result { get; } string SavePath { get; } ByteBuffer Buffer { get; } System.Exception ThreadException { get; } } } // end namespacebless-0.6.3/src/buffers/SaveAsOperation.cs000066400000000000000000000105121374060072200204450ustar00rootroot00000000000000// created on 3/28/2005 at 3:19 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.IO; using System.Threading; using Bless.Util; using Mono.Unix; namespace Bless.Buffers { /// /// Saves the contents of a ByteBuffer using an asynchronous threaded model /// public class SaveAsOperation : ThreadedAsyncOperation, ISaveState { protected ByteBuffer byteBuffer; protected long bytesSaved; protected string savePath; FileStream fs; SaveAsStage stageReached; public ByteBuffer Buffer { get {return byteBuffer;} } public string SavePath { get { return savePath; } set { savePath=value; } } public long BytesSaved { get {return bytesSaved;} } public enum SaveAsStage { BeforeCreate, BeforeWrite } public SaveAsStage StageReached { get { return stageReached; } } public SaveAsOperation(ByteBuffer bb, string fn, ProgressCallback pc, AsyncCallback ac, bool glibIdle): base(pc, ac, glibIdle) { byteBuffer=bb; savePath=fn; fs=null; bytesSaved=0; } protected bool CheckFreeSpace(string path, long extraSpace) { try { long freeSpace = Portable.GetAvailableDiskSpace(path); //System.Console.WriteLine("CFS {0}: {1}+{2} {3}", path, freeSpace, extraSpace, byteBuffer.Size); return (freeSpace + extraSpace >= byteBuffer.Size); } catch (NotImplementedException) { return true; } } protected override bool StartProgress() { progressCallback(string.Format(Catalog.GetString("Saving '{0}'"), SavePath), ProgressAction.Message); return progressCallback(((double)bytesSaved)/byteBuffer.Size, ProgressAction.Show); } protected override bool UpdateProgress() { return progressCallback(((double)bytesSaved)/byteBuffer.Size, ProgressAction.Update); } protected override bool EndProgress() { return progressCallback(((double)bytesSaved)/byteBuffer.Size, ProgressAction.Destroy); } protected override void DoOperation() { stageReached = SaveAsStage.BeforeCreate; if (!CheckFreeSpace(Path.GetDirectoryName(savePath), 0)) { string msg = string.Format(Catalog.GetString("There is not enough free space on the device to save file '{0}'."), savePath); throw new IOException(msg); } // try to open in append mode first, so that a sharing violation // doesn't end up with the file truncated (as opposed // to using FileMode.Create) fs = new FileStream(savePath, FileMode.Append, FileAccess.Write); fs.Close(); // do the actual create fs = new FileStream(savePath, FileMode.Create, FileAccess.Write); stageReached = SaveAsStage.BeforeWrite; const int blockSize = 0xffff; byte[] baTemp = new byte[blockSize]; // for every node Util.List.Node node = byteBuffer.segCol.List.First; while (node != null && !cancelled) { // Save the data in the node // in blocks of blockSize each Segment s = node.data; long len = s.Size; long nBlocks = len/blockSize; int last = (int)(len % blockSize); // bytes in last block long i; // for every full block for (i = 0; i < nBlocks; i++) { s.Buffer.Read(baTemp, 0, s.Start + i * blockSize, blockSize); fs.Write(baTemp, 0, blockSize); bytesSaved = (i + 1) * blockSize; if (cancelled) break; } // if last non-full block is not empty if (last != 0 && !cancelled) { s.Buffer.Read(baTemp, 0, s.Start + i * blockSize, last); fs.Write(baTemp, 0, last); } node = node.next; } fs.Close(); fs = null; } protected override void EndOperation() { if (fs != null) { fs.Close(); fs = null; } } } } // end namespace bless-0.6.3/src/buffers/SaveInPlaceOperation.cs000066400000000000000000000116261374060072200214240ustar00rootroot00000000000000// created on 2/24/2008 at 4:04 PM /* * Copyright (c) 2008, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.IO; using System.Threading; using Bless.Util; using Mono.Unix; namespace Bless.Buffers { /// /// Saves the contents of a ByteBuffer using an asynchronous threaded model. /// This class saves the file in place and can only be used if the file size /// has not been changed. It works by just saving the changed parts. /// public class SaveInPlaceOperation : ThreadedAsyncOperation, ISaveState { protected ByteBuffer byteBuffer; protected long bytesSaved; protected string savePath; FileStream fs; SaveInPlaceStage stageReached; public ByteBuffer Buffer { get {return byteBuffer;} } public string SavePath { get { return savePath; } set { savePath = value; } } public long BytesSaved { get {return bytesSaved;} } public enum SaveInPlaceStage { BeforeClose, BeforeWrite } public SaveInPlaceStage StageReached { get { return stageReached; } } public SaveInPlaceOperation(ByteBuffer bb, ProgressCallback pc, AsyncCallback ac, bool glibIdle): base(pc, ac, glibIdle) { byteBuffer = bb; savePath = byteBuffer.Filename; fs = null; bytesSaved = 0; } protected override bool StartProgress() { progressCallback(string.Format(Catalog.GetString("Saving '{0}'"), SavePath), ProgressAction.Message); return progressCallback(((double)bytesSaved) / byteBuffer.Size, ProgressAction.Show); } protected override bool UpdateProgress() { return progressCallback(((double)bytesSaved) / byteBuffer.Size, ProgressAction.Update); } protected override bool EndProgress() { return progressCallback(((double)bytesSaved) / byteBuffer.Size, ProgressAction.Destroy); } protected override void DoOperation() { stageReached = SaveInPlaceStage.BeforeClose; // Open the file for editing. // Do this in the beginning to figure out if we have all the // required permissions before invalidating the byteBuffer. fs = new FileStream(savePath, FileMode.Open, FileAccess.Write, FileShare.ReadWrite); // hold a reference to the bytebuffer's segment collection // because it is lost when the file is closed SegmentCollection segCol = byteBuffer.segCol; // close file if (!cancelled) { // close the file, make sure that File Operations // are temporarily allowed lock(byteBuffer.LockObj) { // CloseFile invalidates the file buffer, // so make sure undo/redo data stays valid byteBuffer.MakePrivateCopyOfUndoRedo(); byteBuffer.FileOperationsAllowed = true; byteBuffer.CloseFile(); byteBuffer.FileOperationsAllowed = false; } } stageReached = SaveInPlaceStage.BeforeWrite; const int blockSize = 0xffff; byte[] baTemp = new byte[blockSize]; // // Just save the changed parts... // Util.List.Node node = segCol.List.First; // hold the mapping of the start of the current segment // (at which offset in the file it is mapped) long mapping = 0; while (node != null && !cancelled) { // Save the data in the node // in blocks of blockSize each Segment s = node.data; // if the segment belongs to the original buffer, skip it if (s.Buffer.GetType() == typeof(FileBuffer)) { mapping += s.Size; node = node.next; continue; } long len = s.Size; long nBlocks = len/blockSize; int last = (int)(len % blockSize); // bytes in last block long i; // move the file cursor to the current mapping fs.Seek(mapping, SeekOrigin.Begin); bytesSaved = mapping; // for every full block for (i = 0; i < nBlocks; i++) { s.Buffer.Read(baTemp, 0, s.Start + i * blockSize, blockSize); fs.Write(baTemp, 0, blockSize); bytesSaved = (i + 1) * blockSize; if (cancelled) break; } // if last non-full block is not empty if (last != 0 && !cancelled) { s.Buffer.Read(baTemp, 0, s.Start + i * blockSize, last); fs.Write(baTemp, 0, last); } mapping += s.Size; node = node.next; } fs.Close(); fs = null; } protected override void EndOperation() { if (fs != null) { fs.Close(); fs = null; } } } } // end namespace bless-0.6.3/src/buffers/SaveOperation.cs000066400000000000000000000107621374060072200201700ustar00rootroot00000000000000// created on 4/5/2005 at 1:04 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.IO; using System.Threading; using Bless.Util; using Mono.Unix; namespace Bless.Buffers { /// /// Saves the contents of a ByteBuffer using an asynchronous threaded model /// public class SaveOperation : ThreadedAsyncOperation, ISaveState { protected ByteBuffer byteBuffer; protected long bytesSaved; protected string savePath; string tempPath; SaveStage stageReached; public ByteBuffer Buffer { get {return byteBuffer;} } public string SavePath { get { return savePath; } set { savePath = value; } } public long BytesSaved { get {return bytesSaved;} } public string TempPath { get { return tempPath;} } public enum SaveStage { BeforeSaveAs, BeforeDelete, BeforeMove } public SaveStage StageReached { get { return stageReached; } } public SaveOperation(ByteBuffer bb, string tempFilename, ProgressCallback pc, AsyncCallback ac, bool glibIdle) : base(pc, ac, glibIdle) { byteBuffer = bb; savePath = byteBuffer.Filename; tempPath = tempFilename; bytesSaved = 0; activateProgress = false; } protected bool CheckFreeSpace(string path, long extraSpace) { try { long freeSpace = Portable.GetAvailableDiskSpace(path); //System.Console.WriteLine("CFS {0}: {1}+{2} {3}", path, freeSpace, extraSpace, byteBuffer.Size); return (freeSpace + extraSpace >= byteBuffer.Size); } catch (NotImplementedException) { return true; } } protected override bool StartProgress() { progressCallback(string.Format(Catalog.GetString("Moving '{0}' to '{1}'"), tempPath, savePath), ProgressAction.Message); return progressCallback(((double)bytesSaved)/byteBuffer.Size, ProgressAction.Show); } protected override bool UpdateProgress() { return progressCallback(((double)bytesSaved)/byteBuffer.Size, ProgressAction.Update); } protected override bool EndProgress() { return progressCallback(((double)bytesSaved)/byteBuffer.Size, ProgressAction.Destroy); } protected override void DoOperation() { SaveAsOperation sao = new SaveAsOperation(byteBuffer, tempPath, this.progressCallback, null, false); stageReached = SaveStage.BeforeSaveAs; // Check for free space for final file // free space for temporary file is checked in sao.DoOperation() if (!CheckFreeSpace(Path.GetDirectoryName(byteBuffer.Filename), byteBuffer.fileBuf.Size)) { string msg = string.Format(Catalog.GetString("There is not enough free space on the device to save file '{0}'."), byteBuffer.Filename); throw new IOException(msg); } // Save ByteBuffer as a temp file sao.OperationThread(); if (sao.Result == ThreadedAsyncOperation.OperationResult.CaughtException) throw sao.ThreadException; else if (sao.Result == ThreadedAsyncOperation.OperationResult.Cancelled) cancelled = true; // if user hasn't cancelled, move temp file to // its final location if (!cancelled) { this.ActivateProgressReport(true); stageReached = SaveStage.BeforeDelete; // Delete here to fail early (before invalidating the byteBuffer) // if there are any issues. if (System.IO.File.Exists(savePath)) System.IO.File.Delete(savePath); // close the file, make sure that File Operations // are temporarily allowed lock(byteBuffer.LockObj) { // CloseFile invalidates the file buffer, // so make sure undo/redo data stays valid byteBuffer.MakePrivateCopyOfUndoRedo(); byteBuffer.FileOperationsAllowed = true; byteBuffer.CloseFile(); byteBuffer.FileOperationsAllowed = false; } stageReached = SaveStage.BeforeMove; System.IO.File.Move(tempPath, savePath); } } protected override void EndOperation() { } } } // end namespace bless-0.6.3/src/buffers/Segment.cs000066400000000000000000000042701374060072200170100ustar00rootroot00000000000000// created on 6/4/2004 at 3:37 PM /* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ namespace Bless.Buffers { ///Represents a portion of a buffer public class Segment { IBuffer buffer; long start; long end; /// Create a segment of a buffer public Segment(IBuffer buffer, long start, long end) { this.buffer = buffer; this.start = start; this.end = end; } ///Does this segment contain an offset public bool Contains(long offset, long mapping) { if (offset >= mapping && offset <= mapping + end - start) return true; else return false; } ///Split a segment into two public Segment SplitAt(long pos) { if (pos > end - start || pos == 0) return null; Segment s = new Segment(buffer, start + pos, end); this.end = start + pos - 1; return s; } public void MakePrivateCopyOfData() { SimpleBuffer sb = new SimpleBuffer(); sb.AppendBuffer(buffer, start, Size); buffer = sb; start = 0; end = sb.Size - 1; } public override string ToString() { return string.Format("({0}->{1})", start, end); } public long Size { get { return end - start + 1; } } public IBuffer Buffer { get { return buffer;} set { buffer = value;} } public long Start { get { return start;} set { start = value; } } public long End { get { return end;} set { end = value; } } } } // end namespace bless-0.6.3/src/buffers/SegmentCollection.cs000066400000000000000000000226311374060072200210250ustar00rootroot00000000000000/* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; namespace Bless.Buffers { ///A collection of buffer segments public class SegmentCollection { Util.List list; // cache Util.List.Node cachedNode; long cachedMapping; public Util.List List { get { return list; } } public SegmentCollection() { list = new Util.List(); } private void InvalidateCache() { cachedNode = null; cachedMapping = 0; } private void SetCache(Util.List.Node n, long map) { cachedNode = n; cachedMapping = map; } ///Append a segment to the collection public void Append(Segment s) { Util.List.Node n = list.Last; if (n != null && n.data != null) { Segment ls = n.data; if ((s.Buffer == ls.Buffer) && (s.Start == ls.End + 1)) { ls.End = s.End; return; } } list.Append(s); } ///Inserts a segment after a node ///and merges them if possible private Util.List.Node InsertAfter(Util.List.Node n, Segment s) { if (n != null && n.data != null) { Segment ls = n.data; if ((s.Buffer == ls.Buffer) && (s.Start == ls.End + 1)) { ls.End = s.End; return n; } } return list.InsertAfter(n, s); } ///Inserts a segment before a node ///and merges them if possible private Util.List.Node InsertBefore(Util.List.Node n, Segment s) { if (n != null && n.data != null) { Segment ls = n.data; if ((s.Buffer == ls.Buffer) && (s.End + 1 == ls.Start)) { ls.Start = s.Start; return n; } } return list.InsertBefore(n, s); } /// ///Find the segment that the given offset is mapped into /// public Segment FindSegment(long offset, out long OutMapping, out Util.List.Node OutNode) { OutMapping = 0; OutNode = null; // if this is the first search // set up things if (cachedNode == null) { if (list.First == null) return null; SetCache(list.First, 0); } Segment s = cachedNode.data; long curMapping = cachedMapping; Util.List.Node curNode = cachedNode; // is the cached node the one we want? if (s.Contains(offset, curMapping) == true) { OutMapping = curMapping; OutNode = curNode; return s; } // search towards the beginning if (offset < curMapping ) { while (curNode.prev != null) { curNode = curNode.prev; s = curNode.data; curMapping -= s.Size ; if (s.Contains(offset, curMapping) == true) { SetCache(curNode, curMapping); OutMapping = curMapping; OutNode = curNode; return s; } } } else { // search towards the end while (curNode.next != null) { curMapping += s.Size; curNode = curNode.next; s = curNode.data; if (s.Contains(offset, curMapping) == true) { SetCache(curNode, curMapping); OutMapping = curMapping; OutNode = curNode; return s; } } } // offset not found but return last accessed node info OutMapping = curMapping; OutNode = curNode; return null; } /// ///Insert (or Append) a segment collection at a given offset /// public void Insert(SegmentCollection sc, long offset) { long mapping; Util.List.Node node; Segment s = FindSegment(offset, out mapping, out node); // offset not found, check if we have to append if (s == null) { if ((node == null && offset == 0 ) || (node != null && offset == mapping + node.data.Size)) { Util.List lst = sc.List; int N = lst.Count; Util.List.Node n = lst.First; for (int i = 0; i < N; i++) { Append(n.data); n = n.next; } } return; } if (mapping == offset) { // start of segment? // insert data from the current node backwards Util.List lst = sc.List; int N = lst.Count; Util.List.Node n = lst.Last; for (int i = 0; i < N; i++) { node = InsertBefore(node, n.data); n = n.prev; } // update cache SetCache(node, mapping); } else { //middle of segment Segment s1 = s.SplitAt(offset - mapping); list.InsertAfter(node, s1); Util.List lst = sc.List; int N = lst.Count; Util.List.Node n = lst.First; for (int i = 0; i < N; i++) { node = InsertAfter(node, n.data); n = n.next; } } } ///Delete a range from the collection public SegmentCollection DeleteRange(long pos1, long pos2) { long mapping1, mapping2; Util.List.Node node1; Util.List.Node node2; // Find the segments of the end points. // Search for the ending point first so that we won't // have to invalidate the cache later Segment s2 = FindSegment(pos2, out mapping2, out node2); Segment s1 = FindSegment(pos1, out mapping1, out node1); if (s1 == null || s2 == null) return null; // ending segment == starting segment // needs special handling #region Special Handling if node1==node2 if (ReferenceEquals(node1, node2)) { bool remove_flag = false; // try to split segment at pos1 Segment s_f = s1.SplitAt(pos1-mapping1); // if we can't, this means that pos1 is // at the beginning of the segment if (s_f == null) { s_f = s1; remove_flag = true; } // try to split s_f at pos2+1 // s_l is the ending part of s1 that we // should keep Segment s_l = s_f.SplitAt(pos2 - pos1 + 1); // if we can't split, this means that pos2 is // at the end of the segment, // otherwise add s_l after node1 (which contains s1) if (s_l != null) list.InsertAfter(node1, s_l); // if we should remove s1 if (remove_flag) { // try to set the cache if (node1.next != null) SetCache(node1.next, mapping1); else if (node1.prev != null) { Segment s = node1.prev.data; SetCache(node1.prev, mapping1 - s.Size); } else InvalidateCache(); list.Remove(node1); } //else leave the cache set as is (node1, mapping1) SegmentCollection s_c = new SegmentCollection(); s_c.Append(s_f); return s_c; } #endregion // try to split the ending segment Segment sl = s2.SplitAt(pos2 - mapping2 + 1); // if we can't, this means that pos2 is the // at the end of the ending segment if (sl == null) sl = s2; // set the whole segment for removal else list.InsertAfter(node2, sl); Util.List.Node n = node1.next; // try to split the starting segment Segment sf = s1.SplitAt(pos1 - mapping1); // if we can't, this means that pos1 is // at the beginning of the starting segment if (sf == null) { sf = s1; // try to set the cache if (node1.prev != null) { Segment s = node1.prev.data; SetCache(node1.prev, mapping1 - s.Size); } else InvalidateCache(); list.Remove(node1); // remove the whole segment } SegmentCollection sc = new SegmentCollection(); // append the first segment sc.Append(sf); // append to new and remove from old // all segments up to node2 while(ReferenceEquals(n, node2) == false) { sc.Append(n.data); Util.List.Node p = n; n = n.next; // Remove() must be placed after n.next // because it sets n.next=null list.Remove(p); } // append and remove node2 list.Remove(n); sc.Append(n.data); return sc; } public SegmentCollection GetRange(long pos1, long pos2) { long mapping1, mapping2; Util.List.Node node1; Util.List.Node node2; // Find the segments of the end points. // Search for the ending point first so that we won't // have to invalidate the cache later Segment s2 = FindSegment(pos2, out mapping2, out node2); Segment s1 = FindSegment(pos1, out mapping1, out node1); if (s1 == null || s2 == null) return null; if (ReferenceEquals(node1, node2)) { SegmentCollection scTemp = new SegmentCollection(); Segment seg = new Segment(s1.Buffer, pos1 - mapping1 + s1.Start, pos2 - mapping1 + s1.Start); scTemp.Append(seg); return scTemp; } // try to split the ending segment Segment sl = new Segment(s2.Buffer, s2.Start, pos2 - mapping2 + s2.Start ); // try to split the starting segment Segment sf = new Segment(s1.Buffer, pos1 - mapping1 + s1.Start, s1.End); SegmentCollection sc = new SegmentCollection(); // append the first segment sc.Append(sf); Util.List.Node n = node1.next; // append to new and remove from old // all segments up to node2 while(ReferenceEquals(n, node2) == false) { sc.Append(new Segment(n.data.Buffer, n.data.Start, n.data.End)); n = n.next; } sc.Append(sl); return sc; } } } // end namespace bless-0.6.3/src/buffers/SimpleBuffer.cs000066400000000000000000000043561374060072200177760ustar00rootroot00000000000000// created on 6/29/2005 at 7:05 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; namespace Bless.Buffers { /// /// A simple and lightweight buffer implementing the Buffer interface /// public class SimpleBuffer : BaseBuffer { byte[] data; public SimpleBuffer() { data=new byte[0]; } public override long Read(byte[] ba, long index, long pos, long len) { Array.Copy(data, pos, ba, index, len); return len; } public override void Append(byte[] d, long index, long length) { if (length == 0) return; if (data.Length > 0) { byte[] tmp = new byte[data.LongLength + length]; data.CopyTo(tmp, 0); Array.Copy(d, index, tmp, data.LongLength, length); data = tmp; } else { data = new byte[length]; Array.Copy(d, index, data, 0, length); } } public override void AppendBuffer(IBuffer buf, long index, long length) { if (length == 0) return; if (data.Length > 0) { byte[] tmp = new byte[data.LongLength + length]; data.CopyTo(tmp, 0); buf.Read(tmp, data.LongLength, index, length); data = tmp; } else { data = new byte[length]; buf.Read(data, 0, index, length); } } public override byte this[long index] { set { if (index >= data.LongLength) return; data[index]=value; } get { if (index >= data.LongLength) return 0; return data[index]; } } public override long Size { get { return data.LongLength; } } } } // end namespace bless-0.6.3/src/gui/000077500000000000000000000000001374060072200142045ustar00rootroot00000000000000bless-0.6.3/src/gui/DataBook.cs000066400000000000000000000157771374060072200162400ustar00rootroot00000000000000// created on 12/14/2004 at 4:23 PM /* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using Gtk; using Gdk; using System; using System.IO; using Bless.Buffers; namespace Bless.Gui { ///A delegate to call when a databook is closed public delegate void CloseViewDelegate(DataView dv); ///A notebook containing DataViews public class DataBook : Gtk.Notebook { public DataBook() { this.Scrollable = true; this.CanFocus = true; this.EnablePopup = false; } ///Insert a DataView into the databook. public void InsertView(DataView dv, CloseViewDelegate deleg, string text, int pos) { base.InsertPage(dv.Display, new DataBookTabLabel(dv, deleg, text), pos); this.ShowAll(); dv.Buffer.Changed += new ByteBuffer.ChangedHandler(OnBufferContentsChanged); dv.BufferChanged += new DataView.DataViewEventHandler(OnBufferChanged); if (PageAdded != null) PageAdded(dv); // this must be placed after the page added signal, // so that the page change is caught by others (eg EditOperationsPlugin) this.CurrentPage = pos; this.FocusChild = dv.Display; } ///Append a DataView to the databook. public void AppendView(DataView dv, CloseViewDelegate deleg, string text) { this.InsertView(dv, deleg, text, this.NPages); } ///Remove a DataView from databook. public void RemoveView(DataView dv) { dv.Buffer.Changed -= new ByteBuffer.ChangedHandler(OnBufferContentsChanged); dv.BufferChanged -= new DataView.DataViewEventHandler(OnBufferChanged); ((DataBookTabLabel)this.GetTabLabel(dv.Display)).Cleanup(); this.RemovePage(this.PageNum(dv.Display)); if (PageRemoved != null) PageRemoved(dv); } ///Replace a DataView from databook with a new one. public void ReplaceView(DataView oldDv, DataView newDv, CloseViewDelegate deleg, string text) { // find pos of old dataview int pos = this.PageNum(oldDv.Display); RemoveView(oldDv); InsertView(newDv, deleg, text, pos); } /// /// Whether a databook page can be replaced by a new one. /// public bool CanReplacePage(int nPage) { // if there isn't such a page, it can't be replaced if (nPage >= this.NPages || nPage < 0) return false; DataView dv = ((DataViewDisplay)this.GetNthPage(nPage)).View; ByteBuffer bb = dv.Buffer; if (bb.HasChanged == false && bb.Size == 0 && !bb.HasFile) return true; else return false; } /// /// Sets the sensitivity status of the close button of a tab containing 'w'. /// public void SetCloseSensitivity(Widget w, bool sensitive) { DataBookTabLabel dbt = (DataBookTabLabel)this.GetTabLabel(w); dbt.Button.Sensitive = sensitive; } /// /// Sets the text on tab label of the tab containg 'w'. /// public new void SetTabLabelText(Widget w, string text) { DataBookTabLabel dbt = (DataBookTabLabel)this.GetTabLabel(w); dbt.Text = text; } /// /// Updates the title of the tab with the specified DataView /// void UpdateTabLabel(DataView dv) { ByteBuffer bb = dv.Buffer; if (bb.HasChanged) SetTabLabelText(dv.Display, System.IO.Path.GetFileName(bb.Filename) + "*"); else SetTabLabelText(dv.Display, System.IO.Path.GetFileName(bb.Filename)); } protected override bool OnKeyPressEvent(Gdk.EventKey e) { int page = -1; // if alt is pressed if ((e.State & ModifierType.Mod1Mask) == ModifierType.Mod1Mask) { // select a page switch (e.Key) { case Gdk.Key.Key_1: page = 0; break; case Gdk.Key.Key_2: page = 1; break; case Gdk.Key.Key_3: page = 2; break; case Gdk.Key.Key_4: page = 3; break; case Gdk.Key.Key_5: page = 4; break; case Gdk.Key.Key_6: page = 5; break; case Gdk.Key.Key_7: page = 6; break; case Gdk.Key.Key_8: page = 7; break; case Gdk.Key.Key_9: page = 8; break; case Gdk.Key.Left: page = this.CurrentPage - 1; break; case Gdk.Key.Right: page = this.CurrentPage + 1; break; default: break; } } // change the current page if the new one is valid if (page >= 0 && page < this.NPages) this.Page = page; return true; } protected override bool OnKeyReleaseEvent(Gdk.EventKey k) { return true; } void OnBufferChanged(DataView dv) { UpdateTabLabel(dv); } ///Handle ByteBuffer changes void OnBufferContentsChanged(ByteBuffer bb) { Gtk.Application.Invoke(delegate { DataView dv = null; // find DataView that owns bb foreach (DataViewDisplay dvtemp in this.Children) { if (dvtemp.View.Buffer == bb) { dv = dvtemp.View; break; } } UpdateTabLabel(dv); }); } public new event DataView.DataViewEventHandler PageAdded; public new event DataView.DataViewEventHandler PageRemoved; } ///A widget to display on each tab label class DataBookTabLabel : Gtk.HBox { Gtk.Label label; Gtk.Button closeButton; DataView dataView; CloseViewDelegate doCloseFile; public string Text { get { return label.Text; } set { label.Text = value; } } public Gtk.Button Button { get { return closeButton; } } public DataBookTabLabel(DataView dv, CloseViewDelegate deleg, string str) { dataView = dv; doCloseFile = deleg; dataView.NotificationChanged += OnNotificationChanged; label = new Gtk.Label(str); label.UseMarkup = true; label.UseUnderline = false; Gtk.Image img = new Gtk.Image(Gtk.Stock.Close, Gtk.IconSize.Menu); img.SetSizeRequest(8, 8); // This doesn't compile in 1.0.2 and older, // keep it for later eg gtk# 2.0 closeButton = new Gtk.Button(img); closeButton.Relief = Gtk.ReliefStyle.None; closeButton.Clicked += OnCloseClicked; closeButton.CanFocus = false; this.Spacing = 2; this.PackStart(label, false, false, 0); this.PackStart(closeButton, false, false, 0); this.ShowAll(); } private void OnNotificationChanged(DataView dv) { if (dv.Notification == true) { label.Markup = "" + label.Text + ""; } else { label.Markup = label.Text; } } private void OnCloseClicked(object o, EventArgs args) { doCloseFile(dataView); } public void Cleanup() { dataView.NotificationChanged -= OnNotificationChanged; dataView = null; } } } bless-0.6.3/src/gui/DataBookFinder.cs000066400000000000000000000270021374060072200173500ustar00rootroot00000000000000// created on 1/17/2005 at 5:00 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.Text; using System.Threading; using Bless.Util; using Bless.Buffers; using Bless.Tools.Find; namespace Bless.Gui { public class DataBookFinder : IFinder { DataBook dataBook; IFindStrategy strategy; Bless.Util.Range lastFound; Bless.Util.Range threadResult; // the result of the search thread Thread findThread; public event FirstFindHandler FirstFind; ProgressCallback progressCallback; // callback for progress reporting AsyncCallback userFindAsyncCallback; AutoResetEvent findFinishedEvent; // // shared between main and ReplaceAll threads Bless.Util.Range firstMatch; int numReplaced; bool firstTime; // The find progress handler runs an iteration of the application // event loop to make the gui more responsive. During such an iteration // an event may arrive and trigger again a DataBookFinder method (in the same // thread) but DataBookFinder methods are not re-entrant. The inUse variable // is used to check if the DataBookFinder is already in use and disallow such // a re-entrance. bool inUse; public DataBookFinder(DataBook db, ProgressCallback pc) { // connect with databook dataBook = db; lastFound = new Bless.Util.Range(); firstTime = true; inUse = false; progressCallback = pc; // initialize events findFinishedEvent = new AutoResetEvent(false); } public IFindStrategy Strategy { get { return strategy;} set { strategy = value; } } public Bless.Util.Range LastFound { get { return lastFound;} set { lastFound = value; } } ///Sets up the messages displayed when reporting the search progress void SetUpFindProgressReport() { progressCallback("Searching", ProgressAction.Message); StringBuilder details = new StringBuilder(); details.AppendFormat("File: {0}", strategy.Buffer.Filename); progressCallback(details.ToString(), ProgressAction.Details); } ///Sets up the messages displayed when reporting the replace all progress void SetUpReplaceAllProgressReport() { progressCallback("Replacing All", ProgressAction.Message); StringBuilder details = new StringBuilder(); details.AppendFormat("File: {0}", strategy.Buffer.Filename); progressCallback(details.ToString(), ProgressAction.Details); } /// /// Handles operations that will surely produce on result (eg when /// no DataView exists). /// IAsyncResult HandleProblematicOp(GenericFindOperation op, AsyncCallback ac) { op.Result = GenericFindOperation.OperationResult.Finished; findFinishedEvent.Reset(); IAsyncResult iar = new ThreadedAsyncResult(op, findFinishedEvent, true); if (ac != null) ac(iar); findFinishedEvent.Set(); return iar; } /// /// Find the next occurence of the byte pattern. Works asynchronously. /// public IAsyncResult FindNext(AsyncCallback ac) { if (dataBook.NPages == 0 || inUse) { FindNextOperation op = new FindNextOperation(strategy, null, FindAsyncCallback); return HandleProblematicOp(op, ac); } inUse = true; userFindAsyncCallback = ac; findFinishedEvent.Reset(); // if this is the first time we are checking // for a valid pattern, emit the event if (firstTime == true && strategy.Pattern.Length > 0) { firstTime = false; if (FirstFind != null) FirstFind(); } // is pattern acceptable? else if (strategy.Pattern.Length == 0) return null; DataView dv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; strategy.Buffer = dv.Buffer; // decide where to start searching from if (!dv.Selection.IsEmpty()) strategy.Position = dv.Selection.Start + 1; else strategy.Position = dv.CursorOffset; SetUpFindProgressReport(); FindNextOperation fno = new FindNextOperation(strategy, progressCallback, FindAsyncCallback); // lock the buffer, so user can't modify it while // searching strategy.Buffer.ModifyAllowed = false; strategy.Buffer.FileOperationsAllowed = false; // start find thread Thread findThread = new Thread(fno.OperationThread); findThread.IsBackground = true; findThread.Start(); return new ThreadedAsyncResult(fno, findFinishedEvent, false); } /// /// Find the previous occurence of the byte pattern. Works asynchronously. /// public IAsyncResult FindPrevious(AsyncCallback ac) { if (dataBook.NPages == 0 || inUse) { FindPreviousOperation op = new FindPreviousOperation(strategy, null, FindAsyncCallback); return HandleProblematicOp(op, ac); } inUse = true; userFindAsyncCallback = ac; findFinishedEvent.Reset(); // if this is the first time we are checking // for a valid pattern, emit the event if (firstTime == true && strategy.Pattern.Length > 0) { firstTime = false; if (FirstFind != null) FirstFind(); } // is pattern acceptable? else if (strategy.Pattern.Length == 0) return null; DataView dv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; strategy.Buffer = dv.Buffer; // decide where to start searching from if (!dv.Selection.IsEmpty()) strategy.Position = dv.Selection.End; else strategy.Position = dv.CursorOffset; SetUpFindProgressReport(); FindPreviousOperation fpo = new FindPreviousOperation(strategy, progressCallback, FindAsyncCallback); // lock the buffer, so user can't modify it while // searching strategy.Buffer.ModifyAllowed = false; strategy.Buffer.FileOperationsAllowed = false; // start find thread Thread findThread = new Thread(fpo.OperationThread); findThread.IsBackground = true; findThread.Start(); return new ThreadedAsyncResult(fpo, findFinishedEvent, false); } /// /// Called when an asynchronous Find Next/Previous operation finishes. /// void FindAsyncCallback(IAsyncResult ar) { GenericFindOperation state = (GenericFindOperation)ar.AsyncState; ThreadedAsyncOperation.OperationResult result = state.Result; Util.Range match = state.Match; DataView dv = null; // find DataView that owns bb foreach (DataViewDisplay dvtemp in dataBook.Children) { if (dvtemp.View.Buffer == strategy.Buffer) { dv = dvtemp.View; break; } } // decide what to do based on the result of the find operation switch (result) { case ThreadedAsyncOperation.OperationResult.Finished: if (match != null) { lastFound = match; dv.SetSelection(match.Start, match.End);//System.Console.WriteLine("Found at {0}-{1}", r.Start, r.End); dv.MoveCursor(match.End + 1, 0); dv.Display.MakeOffsetVisible(match.Start, DataViewDisplay.ShowType.Closest); } else { lastFound.Clear(); } break; case ThreadedAsyncOperation.OperationResult.Cancelled: dv.MoveCursor(strategy.Position, 0); dv.Display.MakeOffsetVisible(strategy.Position, DataViewDisplay.ShowType.Closest); break; case ThreadedAsyncOperation.OperationResult.CaughtException: break; default: break; } inUse = false; // if user provided a callback, call it now if (userFindAsyncCallback != null) userFindAsyncCallback(ar); // notify that the find operation has finished findFinishedEvent.Set(); } ///Check if the specified range of bytes in a ByteBuffer equals a byte pattern bool RangeEqualsPattern(ByteBuffer bb, Bless.Util.Range sel, byte[] pattern) { int i = 0; int len = pattern.Length; if (sel.IsEmpty()) return false; while (i < len && pattern[i] == bb[sel.Start+i]) i++; if (i != len) return false; else return true; } /// /// Replace the last match with a pattern. /// Returns whether the replace operation was succesful. /// public bool Replace(byte[] ba) { if (dataBook.NPages == 0) return false; // DataBookFinder is already in use if (inUse) return true; inUse = true; DataView dv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; if (RangeEqualsPattern(dv.Buffer, dv.Selection, strategy.Pattern)) { dv.Buffer.Replace(dv.Selection.Start, dv.Selection.End, ba); dv.CursorUndoDeque.AddFront(new CursorState(dv.Selection.Start, 0, dv.Selection.Start + ba.Length, 0)); dv.CursorRedoDeque.Clear(); dv.MoveCursor(dv.Selection.Start + ba.Length, 0); dv.SetSelection(-1, -1); lastFound.Clear(); inUse = false; return true; } inUse = false; return false; } /// /// Replace all matches with a pattern. Works asynchronously. /// public IAsyncResult ReplaceAll(byte[] ba, AsyncCallback ac) { if (dataBook.NPages == 0 || inUse) { ReplaceAllOperation op = new ReplaceAllOperation(strategy, null, ReplaceAllAsyncCallback, ba); return HandleProblematicOp(op, ac); } // DataBookFinder is already in use if (inUse) return null; inUse = true; userFindAsyncCallback = ac; DataView dv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; // initialize strategy strategy.Buffer = dv.Buffer; strategy.Position = 0; SetUpReplaceAllProgressReport(); ReplaceAllOperation rao = new ReplaceAllOperation(strategy, progressCallback, ReplaceAllAsyncCallback, ba); findFinishedEvent.Reset(); // don't allow messing up with the buffer // start replace all thread Thread findThread = new Thread(rao.OperationThread); findThread.IsBackground = true; findThread.Start(); return new ThreadedAsyncResult(rao, findFinishedEvent, false); } /// /// Called when an asynchronous Replace All operation finishes. /// void ReplaceAllAsyncCallback(IAsyncResult ar) { ReplaceAllOperation state = (ReplaceAllOperation)ar.AsyncState; ThreadedAsyncOperation.OperationResult result = state.Result; Util.Range firstMatch = state.FirstMatch; DataView dv = null; // find DataView that owns bb foreach (DataViewDisplay dvtemp in dataBook.Children) { if (dvtemp.View.Buffer == strategy.Buffer) { dv = dvtemp.View; break; } } // decide what to do based on the result of the Replace All operation if (result == ThreadedAsyncOperation.OperationResult.Cancelled) { dv.Buffer.Undo(); } // if we have replaced at least one occurence, else if (result == ThreadedAsyncOperation.OperationResult.Finished && firstMatch != null) { lastFound = state.Match; // save the cursor state for undo/redo dv.CursorUndoDeque.AddFront(new CursorState(firstMatch.Start, 0, lastFound.Start + state.ReplacePattern.Length, 0)); // move cursor after final replacement dv.SetSelection(-1, -1); dv.MoveCursor(lastFound.Start + state.ReplacePattern.Length, 0); dv.Display.MakeOffsetVisible(lastFound.Start + state.ReplacePattern.Length, DataViewDisplay.ShowType.Closest); } inUse = false; // if user provided a callback, call it now if (userFindAsyncCallback != null) userFindAsyncCallback(ar); // notify that the replace all operation has finished findFinishedEvent.Set(); } } } // end namespace bless-0.6.3/src/gui/DataView.cs000066400000000000000000000423371374060072200162500ustar00rootroot00000000000000// created on 6/14/2004 at 10:35 PM /* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System.Collections; using System; using Gtk; using Bless.Buffers; using Bless.Gui.Areas; using Bless.Gui.Drawers; using Bless.Util; using Bless.Tools; namespace Bless.Gui { ///An interface to a widget that displays data from a buffer public class DataView { Layout layout; ByteBuffer byteBuffer; Gtk.VScrollbar vscroll; bool widgetRealized; string prefID; DataViewControl dvControl; DataViewDisplay dvDisplay; // clipboard related byte[] clipdata; Gtk.Clipboard clipboard; static TargetEntry[] clipboardTargets = new TargetEntry[]{ new TargetEntry("application/octet-stream", 0, 0), new TargetEntry("UTF8_STRING", 0, 0) }; bool overwrite; bool notification; //undo-redo related Deque cursorUndoDeque; Deque cursorRedoDeque; public Deque CursorUndoDeque { get { return cursorUndoDeque; } } public Deque CursorRedoDeque { get { return cursorRedoDeque; } } public DataViewControl Control { get { return dvControl; } } public DataViewDisplay Display { get { return dvDisplay; } } public ByteBuffer Buffer { get { return byteBuffer; } set { if (value != null) SetupByteBuffer(value); else CleanupByteBuffer(); } } public bool Overwrite { set { overwrite = value; if (OverwriteChanged != null) OverwriteChanged(this); } get { return overwrite; } } public Area FocusedArea { get { return dvDisplay.Layout.AreaGroup.FocusedArea; } } /// /// Whether the DataView should notify the user /// that something important is going on /// public bool Notification { get { return notification; } set { notification = value; if (NotificationChanged != null) NotificationChanged(this); } } private void OnByteBufferChanged(ByteBuffer bb) { Gtk.Application.Invoke(delegate { if (byteBuffer.ReadAllowed) dvDisplay.Layout.AreaGroup.RedrawNow(); }); } private void OnByteBufferFileChanged(ByteBuffer bb) { Gtk.Application.Invoke(delegate { dvDisplay.ShowFileChangedBar(); Notification = true; byteBuffer.FileOperationsAllowed = false; }); } void OnPreferencesChanged(Preferences prefs) { if (byteBuffer == null) return; string undoLimited = prefs["Undo.Limited"]; string undoActions = prefs["Undo.Actions"]; if (undoLimited == "True") { byteBuffer.MaxUndoActions = Int32.Parse(undoActions); while (cursorUndoDeque.Count > byteBuffer.MaxUndoActions) cursorUndoDeque.RemoveEnd(); } else byteBuffer.MaxUndoActions = -1; // temp dir byteBuffer.TempDir = prefs["ByteBuffer.TempDir"]; } void AddUndoCursorState(CursorState state) { if (byteBuffer.MaxUndoActions != -1) while (cursorUndoDeque.Count >= byteBuffer.MaxUndoActions) cursorUndoDeque.RemoveEnd(); cursorUndoDeque.AddFront(state); } private void DeleteSelectionInternal() { AreaGroup areaGroup = dvDisplay.Layout.AreaGroup; // // set cursor and selection before deleting so that the view remains in a consistent state // (eg the selection isn't beyond the EOF) // Util.Range prevSelection = this.Selection; AddUndoCursorState(new CursorState(areaGroup.CursorOffset, 0, areaGroup.Selection.Start, 0)); cursorRedoDeque.Clear(); this.MoveCursor(areaGroup.Selection.Start, 0); this.SetSelection(-1, -1); byteBuffer.Delete(prevSelection.Start, prevSelection.End); } //Called when an application wants to get our clipboard data private void OnClipboardGet(Clipboard cb, SelectionData sd, uint n) { // if application accepts text if (sd.Target.Name == "UTF8_STRING") { switch (this.FocusedArea.Type) { case "hexadecimal": sd.Text = ByteArray.ToString(clipdata, 16); break; case "decimal": sd.Text = ByteArray.ToString(clipdata, 10); break; case "octal": sd.Text = ByteArray.ToString(clipdata, 8); break; case "binary": sd.Text = ByteArray.ToString(clipdata, 2); break; case "ascii": sd.Set(sd.Target, 8, clipdata); break; default: break; } } // if application accepts raw bytes else if (sd.Target.Name == "application/octet-stream") { sd.Set(sd.Target, 8, clipdata); } } private void OnClipboardClear(Clipboard cb) { } ///Returns any clipboard data we can accept private byte[] GetPasteData() { byte[] data = null; SelectionData sd = clipboard.WaitForContents(Gdk.Atom.Intern("application/octet-stream", false)); // if there are no octet-stream data, try UTF8_STRING // and try to convert it to bytes if (sd == null) { sd = clipboard.WaitForContents(Gdk.Atom.Intern("UTF8_STRING", false)); if (sd != null) { try { // parse string according to currently focused area switch (this.FocusedArea.Type) { case "hexadecimal": data = ByteArray.FromString(sd.Text, 16); break; case "decimal": data = ByteArray.FromString(sd.Text, 10); break; case "octal": data = ByteArray.FromString(sd.Text, 8); break; case "binary": data = ByteArray.FromString(sd.Text, 2); break; case "ascii": data = sd.Data; break; default: break; } } catch (FormatException) { // if string cannot be parsed, consider it as plain text data = sd.Data; } } } else // found octet-stream data data = sd.Data; return data; } ///Create a DataView public DataView() { dvControl = new DataViewControl(this); dvDisplay = new DataViewDisplay(this); dvDisplay.Control = dvControl; dvControl.Display = dvDisplay; // initialize clipdata buffer // and clipboard clipdata = new byte[0]; clipboard = Gtk.Clipboard.Get(Gdk.Atom.Intern("CLIPBOARD", true)); // initialize undo/redo cursor offset stacks cursorUndoDeque = new Deque(); cursorRedoDeque = new Deque(); prefID = "dv" + this.GetHashCode().ToString(); PreferencesChangedHandler handler = new PreferencesChangedHandler(OnPreferencesChanged); Preferences.Proxy.Subscribe("Undo.Limited", prefID, handler); Preferences.Proxy.Subscribe("Undo.Actions", prefID, handler); Preferences.Proxy.Subscribe("Highlight.PatternMatch", prefID, handler); Preferences.Proxy.Subscribe("ByteBuffer.TempDir", prefID, handler); } public void Copy() { AreaGroup areaGroup = dvDisplay.Layout.AreaGroup; if (areaGroup.Areas.Count <= 0) return; if (!byteBuffer.ReadAllowed) return; byte[] ba = byteBuffer.RangeToByteArray(areaGroup.Selection); // if no selection, do nothing (keep old clipboard data) if (ba == null) return; clipdata = ba; // set clipboard clipboard.SetWithData(clipboardTargets, new ClipboardGetFunc(OnClipboardGet), new ClipboardClearFunc(OnClipboardClear)); dvDisplay.MakeOffsetVisible(areaGroup.CursorOffset, DataViewDisplay.ShowType.Closest); } public void Cut() { AreaGroup areaGroup = dvDisplay.Layout.AreaGroup; if (areaGroup.Areas.Count <= 0) return; // if we can't modify the buffer... if (!byteBuffer.ModifyAllowed) return; // if the buffer isn't resizable... if (!byteBuffer.IsResizable) { return; } byte[] ba = byteBuffer.RangeToByteArray(areaGroup.Selection); // if no selection, do nothing (keep old clipboard data) if (ba == null) return; clipdata = ba; // set clipboard clipboard.SetWithData(clipboardTargets, new ClipboardGetFunc(OnClipboardGet), new ClipboardClearFunc(OnClipboardClear)); this.DeleteSelectionInternal(); // Make sure dataView.Redraw() is called before dvDisplay.MakeOffsetVisible() // so that the Scrollbar has the correct range // when calling dataView.Goto(). // dataView.Redraw(); dvDisplay.MakeOffsetVisible(areaGroup.CursorOffset, DataViewDisplay.ShowType.Closest); } public void Paste() { AreaGroup areaGroup = dvDisplay.Layout.AreaGroup; if (areaGroup.Areas.Count <= 0) return; // if we can't modify the buffer... if (!byteBuffer.ModifyAllowed) return; // if the buffer isn't resizable, ignore non-overwriting paste if (!byteBuffer.IsResizable && !overwrite) { return; } // get data from clipboard byte[] pasteData = GetPasteData(); // if there wasn't any suitable data, return if (pasteData == null || pasteData.Length == 0) return; // if no range is selected insert/overtwrite the data and move // cursor to the end of inserted data if (areaGroup.Selection.IsEmpty()){ // if user wants to overwrite and there is something to overwrite... // There is something to overwrite if we are not pasting at the end // of the file. if (overwrite == true && areaGroup.CursorOffset < byteBuffer.Size) { long endPos = areaGroup.CursorOffset + pasteData.Length - 1; if (endPos >= byteBuffer.Size) endPos = byteBuffer.Size - 1; byteBuffer.Replace(areaGroup.CursorOffset, endPos, pasteData); } else // if user doesn't want to overwrite or there is nothing to overwrite byteBuffer.Insert(areaGroup.CursorOffset, pasteData, 0, pasteData.LongLength); AddUndoCursorState(new CursorState(areaGroup.CursorOffset, 0, areaGroup.CursorOffset + pasteData.Length, 0)); cursorRedoDeque.Clear(); this.MoveCursor(areaGroup.CursorOffset + pasteData.Length, 0); } else { // if a range is selected, replace the range with // the data and move the cursor to the end of // the new data byteBuffer.Replace(areaGroup.Selection.Start, areaGroup.Selection.End, pasteData); AddUndoCursorState(new CursorState(areaGroup.Selection.Start, 0, areaGroup.Selection.Start + pasteData.Length, 0)); cursorRedoDeque.Clear(); this.MoveCursor(areaGroup.Selection.Start + pasteData.Length, 0); this.SetSelection(-1, -1); } // Make sure dataView.Redraw() is called before dvDisplay.MakeOffsetVisible() // so that the Scrollbar has the correct range // when calling dvDisplay.MakeOffsetVisible(). // dataView.Redraw(); dvDisplay.MakeOffsetVisible(areaGroup.CursorOffset, DataViewDisplay.ShowType.Closest); } public void Delete() { AreaGroup areaGroup = dvDisplay.Layout.AreaGroup; if (areaGroup.Areas.Count <= 0) return; // if we can't modify the buffer... if (!byteBuffer.ModifyAllowed) return; // if nothing is selected, delete the byte at the current offset if (areaGroup.Selection.IsEmpty() == true) { if (areaGroup.CursorOffset < byteBuffer.Size) { byteBuffer.Delete(areaGroup.CursorOffset, areaGroup.CursorOffset); AddUndoCursorState(new CursorState(areaGroup.CursorOffset, areaGroup.CursorDigit, areaGroup.CursorOffset, areaGroup.CursorDigit)); cursorRedoDeque.Clear(); } } else { // delete the selection DeleteSelectionInternal(); } dvDisplay.MakeOffsetVisible(areaGroup.CursorOffset, DataViewDisplay.ShowType.Closest); } public void DeleteBackspace() { AreaGroup areaGroup = dvDisplay.Layout.AreaGroup; if (areaGroup.Areas.Count <= 0) return; if (!byteBuffer.ModifyAllowed) return; // if nothing is selected, delete the byte at the previous offset if (areaGroup.Selection.IsEmpty() == true) { long cOffset = areaGroup.CursorOffset; if (cOffset > 0) { this.MoveCursor(cOffset - 1, areaGroup.CursorDigit); byteBuffer.Delete(cOffset - 1, cOffset - 1); AddUndoCursorState(new CursorState(cOffset, areaGroup.CursorDigit, cOffset - 1, areaGroup.CursorDigit)); cursorRedoDeque.Clear(); } } else { // delete the selection DeleteSelectionInternal(); } dvDisplay.MakeOffsetVisible(areaGroup.CursorOffset, DataViewDisplay.ShowType.Closest); } public void Undo() { // if we can't modify the buffer... if (!byteBuffer.ModifyAllowed) return; // undo buffer changes byteBuffer.Undo(); // restore cursor position if (cursorUndoDeque.Count > 0) { CursorState ch = (CursorState)cursorUndoDeque.RemoveFront(); cursorRedoDeque.AddFront(ch); // clear the selection this.SetSelection(-1, -1); dvDisplay.MakeOffsetVisible(ch.UndoOffset, DataViewDisplay.ShowType.Closest); this.MoveCursor(ch.UndoOffset, ch.UndoDigit); } } public void Redo() { // if we can't modify the buffer... if (!byteBuffer.ModifyAllowed) return; // redo buffer changes byteBuffer.Redo(); // restore cursor position if (cursorRedoDeque.Count > 0) { CursorState ch = (CursorState)cursorRedoDeque.RemoveFront(); AddUndoCursorState(ch); // clear the selection this.SetSelection(-1, -1); dvDisplay.MakeOffsetVisible(ch.RedoOffset, DataViewDisplay.ShowType.Closest); this.MoveCursor(ch.RedoOffset, ch.RedoDigit); } } public void Revert() { // if we can't modify the buffer... if (!byteBuffer.ModifyAllowed) return; byteBuffer.Revert(); cursorRedoDeque.Clear(); cursorUndoDeque.Clear(); MoveCursor(0, 0); } private void SetupByteBuffer(ByteBuffer bb) { byteBuffer = bb; byteBuffer.Changed += OnByteBufferChanged; byteBuffer.FileChanged += OnByteBufferFileChanged; AreaGroup areaGroup = dvDisplay.Layout.AreaGroup; areaGroup.Buffer = byteBuffer; areaGroup.SetCursor(0, 0); areaGroup.Selection = new Util.Range(); dvDisplay.Redraw(); dvDisplay.VScroll.Adjustment.Value = 0; OnPreferencesChanged(Preferences.Instance); if (BufferChanged != null) BufferChanged(this); } private void CleanupByteBuffer() { if (byteBuffer != null) { byteBuffer.Changed -= OnByteBufferChanged; byteBuffer.FileChanged -= OnByteBufferFileChanged; } AreaGroup areaGroup = dvDisplay.Layout.AreaGroup; areaGroup.Buffer = null; areaGroup.SetCursor(0, 0); areaGroup.Selection.Clear(); byteBuffer = null; } public void Cleanup() { this.Buffer = null; // all these to help the GC... dvDisplay.Cleanup(); dvDisplay = null; dvControl.Cleanup(); dvControl = null; Preferences.Proxy.Unsubscribe("Undo.Limited", prefID); Preferences.Proxy.Unsubscribe("Undo.Actions", prefID); Preferences.Proxy.Unsubscribe("Highlight.PatternMatch", prefID); Preferences.Proxy.Unsubscribe("ByteBuffer.TempDir", prefID); } /// /// Sets the current selection. It makes sure that the selection is sorted. /// public void SetSelection(long start, long end) { AreaGroup areaGroup = dvDisplay.Layout.AreaGroup; // check whether the selection has really // changed... if (areaGroup.Areas.Count <= 0) return; Bless.Util.IRange sel = areaGroup.Selection; // if there is no change, don't do anything if (sel.Start == start && sel.End == end) return; Bless.Util.Range newSel = new Bless.Util.Range(start, end); newSel.Sort(); areaGroup.Selection = newSel; if (SelectionChanged != null) SelectionChanged(this); } public Bless.Util.Range Selection { get { AreaGroup areaGroup = dvDisplay.Layout.AreaGroup; if (areaGroup.Areas.Count <= 0) return new Bless.Util.Range(); Bless.Util.Range r = areaGroup.Selection; return new Bless.Util.Range(r); } set { this.SetSelection(value.Start, value.End); } } public void MoveCursor(long offset, int digit) { AreaGroup areaGroup = dvDisplay.Layout.AreaGroup; areaGroup.SetCursor(offset, digit); if (CursorChanged != null) CursorChanged(this); } public long CursorOffset { get { AreaGroup areaGroup = dvDisplay.Layout.AreaGroup; return areaGroup.CursorOffset; } } public int CursorDigit { get { AreaGroup areaGroup = dvDisplay.Layout.AreaGroup; return areaGroup.CursorDigit; } } public long Offset { get { AreaGroup areaGroup = dvDisplay.Layout.AreaGroup; return areaGroup.Offset; } set { AreaGroup areaGroup = dvDisplay.Layout.AreaGroup; areaGroup.Offset = value; } } public delegate void DataViewEventHandler(DataView dv); /// /// Fire the FocusChangedEvent /// public void FireFocusChangedEvent() { if (FocusChanged != null) FocusChanged(this); } // events public event DataViewEventHandler BufferChanged; public event DataViewEventHandler SelectionChanged; public event DataViewEventHandler CursorChanged; public event DataViewEventHandler OverwriteChanged; public event DataViewEventHandler NotificationChanged; public event DataViewEventHandler FocusChanged; }// end DataView // class to store cursor position for undo/redo public class CursorState { public long UndoOffset; public int UndoDigit; public long RedoOffset; public int RedoDigit; public CursorState(long uo, int ud, long ro, int rd) { UndoOffset = uo; RedoOffset = ro; UndoDigit = ud; RedoDigit = rd;} } }//namespace bless-0.6.3/src/gui/DataViewControl.cs000066400000000000000000000477121374060072200176130ustar00rootroot00000000000000// created on 12/13/2004 at 1:15 PM /* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using Gtk; using Bless.Buffers; using Bless.Gui.Areas; using Bless.Util; namespace Bless.Gui { ///Handles all dataview ui aspects except display public class DataViewControl { private struct Position { public long First; public long Second; public int Digit; } DataView dataView; DataViewDisplay dvDisplay; // mouse selection related Position selStartPos; Position selEndPos; // Filter keypresses Gtk.IMContext imContext; public DataViewDisplay Display { get { return dvDisplay;} set { dvDisplay = value;} } public DataView View { get { return dataView;} } public DataViewControl(DataView dv) { dataView = dv; selStartPos = new Position(); selEndPos = new Position(); imContext = new IMContextSimple(); } ///Get the area that contains (X,Y) private Area GetAreaByXY(int x, int y) { Area clickArea = null; foreach(Area a in dvDisplay.Layout.AreaGroup.Areas) { if ((x >= a.X) && (x <= a.X + a.Width)) { clickArea = a; break; } } return clickArea; } private void UpdateSelection(bool abyss) { //System.Console.WriteLine("* (1) Start: {0},{1},{2} End: {3},{4},{5}", selStartPos.First, selStartPos.Second, selStartPos.Digit, selEndPos.First, selEndPos.Second, selEndPos.Digit); Bless.Util.Range r; if (selStartPos.Second <= selEndPos.First) r = new Bless.Util.Range(ValidateOffset(selStartPos.Second), ValidateOffset(selEndPos.First)); else r = new Bless.Util.Range(ValidateOffset(selEndPos.Second), ValidateOffset(selStartPos.First)); //System.Console.WriteLine("Selection is ({0}, {1}) Expected ({2}, {3})", dataView.Selection.Start, dataView.Selection.End, r.Start, r.End); // if nothing is selected and cursor position has changed externally if (dataView.Selection.IsEmpty() && dataView.CursorOffset != selStartPos.Second) { long offset = dataView.CursorOffset; selStartPos.First = offset - (abyss ? 1 : 0); selStartPos.Second = offset; selStartPos.Digit = dataView.CursorDigit; selEndPos = selStartPos; //System.Console.WriteLine("* (2) Start: {0},{1},{2} End: {3},{4},{5}", selStartPos.First, selStartPos.Second, selStartPos.Digit, selEndPos.First, selEndPos.Second, selEndPos.Digit); } else if (!dataView.Selection.IsEmpty() && !r.Equals(dataView.Selection)) { selStartPos.Second = dataView.Selection.Start; selStartPos.First = selStartPos.Second - 1; selEndPos.First = dataView.Selection.End; selEndPos.Second = selEndPos.First + 1; } //System.Console.WriteLine("* Selection is ({0}, {1}) Expected ({2}, {3}) Fixed ({4}, {5})", dataView.Selection.Start, dataView.Selection.End, r.Start, r.End, selStartPos.Second, selEndPos.First); } private bool UpdateFocus(Area area) { if (area.CanFocus && !area.HasCursorFocus) { dvDisplay.Layout.AreaGroup.FocusedArea = area; return true; } return false; } private void CalculatePosition(Area area, int x, int y, ref Position pos) { Area.GetOffsetFlags flags; int digit; long off2; long off1 = area.GetOffsetByDisplayInfo(x, y, out digit, out flags); if ((flags & Area.GetOffsetFlags.Eof) == Area.GetOffsetFlags.Eof) { off1 = dataView.Buffer.Size; off2 = off1; } else if ((flags & Area.GetOffsetFlags.Abyss) == Area.GetOffsetFlags.Abyss) { off2 = off1 + 1; } else off2 = off1; pos.First = off1; pos.Second = off2; pos.Digit = digit; } private long ValidateOffset(long offset) { if (offset < 0) return 0; if (offset >= dataView.Buffer.Size) return dataView.Buffer.Size - 1; return offset; } /// /// Sets the selection and the cursor position according to the values of selStartPos, selEndPos /// private void EvaluateSelection(DataViewDisplay.ShowType showType) { //System.Console.WriteLine("Evaluate (1) Start: {0},{1},{2} End: {3},{4},{5}", selStartPos.First, selStartPos.Second, selStartPos.Digit, selEndPos.First, selEndPos.Second, selEndPos.Digit); long cursorOffset; // no selection if (selStartPos.First == selEndPos.First && selStartPos.Second == selEndPos.Second) { cursorOffset = selStartPos.Second; // make sure cursor (or end of selection) is visible dvDisplay.MakeOffsetVisible(cursorOffset, showType); dataView.SetSelection(-1, -1); dataView.MoveCursor(selStartPos.Second, selEndPos.Digit); } // selection with start pos <= end pos else if (selStartPos.Second <= selEndPos.First) { // set end position between bytes // this is done so that selections performed with // the mouse can be continued with the keyboard // (keyboard selections always set positions between bytes) selEndPos.Second = selEndPos.First + 1; // if selEndPos.Second is at or beyond the EOF long off = ValidateOffset(selEndPos.Second); if (selEndPos.First >= off) off++; cursorOffset = off; dvDisplay.MakeOffsetVisible(cursorOffset, showType); // set the selection only if the start position (which is the start of the selection) // is within the file's limits if (selStartPos.Second < dataView.Buffer.Size) dataView.SetSelection(ValidateOffset(selStartPos.Second), ValidateOffset(selEndPos.First)); else dataView.SetSelection(-1, -1); dataView.MoveCursor(off, 0); } // selection with start pos > end pos else { // set start position between bytes // this is done so that selections performed with // the mouse can be continued with the keyboard // (keyboard selections always set positions between bytes) // TODO: This is currently disabled because it breaks mouse // selection // //selStartPos.Second = selStartPos.First + 1; long off = selEndPos.Second; cursorOffset = off; dvDisplay.MakeOffsetVisible(cursorOffset, showType); // set the selection only if the end position (which is the start of the selection) // is within the file's limits if (selEndPos.Second < dataView.Buffer.Size) dataView.SetSelection(ValidateOffset(selEndPos.Second), ValidateOffset(selStartPos.First)); else dataView.SetSelection(-1, -1); dataView.MoveCursor(off, 0); } //System.Console.WriteLine("Evaluate (2) Start: {0},{1},{2} End: {3},{4},{5}", selStartPos.First, selStartPos.Second, selStartPos.Digit, selEndPos.First, selEndPos.Second, selEndPos.Digit); } ///Handle mouse button presses internal void OnButtonPress (object o, ButtonPressEventArgs args) { dvDisplay.GrabKeyboardFocus(); Gdk.EventButton e = args.Event; Area clickArea = GetAreaByXY((int)e.X, (int)e.Y); if (clickArea == null) return; // get the position in the file Position pos = new Position(); CalculatePosition(clickArea, (int)(e.X - clickArea.X), (int)(e.Y - clickArea.Y), ref pos); // right mouse button if (e.Button == 3) { // show the popup clickArea.ShowPopup(Services.UI.Manager); // if there is no selection change the cursor position if (dataView.Selection.IsEmpty()) { selStartPos = pos; selEndPos = pos; } } else { // update selection and cursor if they have changed externally UpdateSelection(pos.First != pos.Second); // if shift is pressed the position is the end position of the selection if ((e.State & Gdk.ModifierType.ShiftMask) != 0) { selEndPos = pos; } else { // ... start a new selection selStartPos = pos; selEndPos = pos; } } // give the focus to the appropriate area // do this before setting the new cursor/selection UpdateFocus(clickArea); EvaluateSelection(DataViewDisplay.ShowType.Closest); } ///Handle mouse motion internal void OnMotionNotify(object o, MotionNotifyEventArgs args) { Gdk.EventMotion e = args.Event; Gtk.DrawingArea da = (Gtk.DrawingArea)o; int x, y; Gdk.ModifierType state; if (e.IsHint) da.GdkWindow.GetPointer(out x, out y, out state); else { x = (int)e.X; y = (int)e.Y; state = e.State; } // if left mouse button is not down if ((state & Gdk.ModifierType.Button1Mask) == 0) return; // find in which area the pointer is Area clickArea = GetAreaByXY(x, y); if (clickArea == null) return; // get the position in the file Position pos = new Position(); CalculatePosition(clickArea, (int)(x - clickArea.X), (int)(y - clickArea.Y), ref pos); // update selection and cursor if they have changed externally UpdateSelection(pos.First != pos.Second); // Evaluate selection before moving the cursor // for better visual result selEndPos = pos; // give the focus to the appropriate area // do this before setting the new cursor/selection UpdateFocus(clickArea); EvaluateSelection(DataViewDisplay.ShowType.Closest); } ///Handle mouse button release internal void OnButtonRelease (object o, ButtonReleaseEventArgs args) { Gdk.EventButton e = args.Event; Area clickArea = GetAreaByXY((int)e.X, (int)e.Y); if (clickArea == null) return; int x = (int)e.X; int y; // if the pointer has moved out of the area height borders // make sure there is consistency in the selection // when depressing the mouse button if (e.Y > clickArea.Height + clickArea.Y) y = clickArea.Height + clickArea.Y - clickArea.Drawer.Height; else if (e.Y < clickArea.Y) y = clickArea.Y; else y = (int)e.Y; // get the position in the file Position pos = new Position(); CalculatePosition(clickArea, (int)(x - clickArea.X), (int)(y - clickArea.Y), ref pos); // update selection and cursor if they have changed externally UpdateSelection(pos.First != pos.Second); // Evaluate selection before moving the cursor // for better visual result selEndPos = pos; //System.Console.WriteLine("Start: {0},{1},{2} End: {3},{4},{5}", selStartPos.First, selStartPos.Second, selStartPos.Digit, selEndPos.First, selEndPos.Second, selEndPos.Digit); // give the focus to the appropriate area // do this before setting the new cursor/selection UpdateFocus(clickArea); EvaluateSelection(DataViewDisplay.ShowType.Closest); } // variables that are shared by OnKeyPress and OnKey* handler methods Area okp_focusArea; int okp_bpr; int okp_dpb; DataViewDisplay.ShowType okp_showType; ///Handle key presses internal void OnKeyPress (object o, KeyPressEventArgs args) { Gdk.EventKey e = args.Event; okp_focusArea = null; bool shiftPressed = false; // find focused area okp_focusArea = dvDisplay.Layout.AreaGroup.FocusedArea; // if no area has the focus, give it to the first one applicable if (okp_focusArea == null) { dvDisplay.Layout.AreaGroup.CycleFocus(); okp_focusArea = dvDisplay.Layout.AreaGroup.FocusedArea; } // if still no area got the focus give up if (okp_focusArea == null) return; okp_bpr = okp_focusArea.BytesPerRow; okp_dpb = okp_focusArea.DigitsPerByte; okp_showType = DataViewDisplay.ShowType.Closest; if ((e.State & Gdk.ModifierType.ShiftMask) == Gdk.ModifierType.ShiftMask) shiftPressed = true; UpdateSelection(true); Position cur = new Position(); if (shiftPressed || !dvDisplay.Layout.AreaGroup.Selection.IsEmpty()) { cur = selEndPos; cur.Digit = 0; } else { cur = selStartPos; } Position next = new Position(); // set next to cur in case it is not set by a keypress handler next = cur; // handle keys bool specialKey = false; switch (e.Key) { case Gdk.Key.Up: OnKeyUp(ref cur, ref next); break; case Gdk.Key.Down: OnKeyDown(ref cur, ref next); break; case Gdk.Key.Left: OnKeyLeft(ref cur, ref next); break; case Gdk.Key.Right: if (shiftPressed) cur.Digit = okp_dpb - 1; OnKeyRight(ref cur, ref next); break; case Gdk.Key.Page_Up: OnKeyPageUp(ref cur, ref next); break; case Gdk.Key.Page_Down: OnKeyPageDown(ref cur, ref next); break; case Gdk.Key.Home: OnKeyHome(ref cur, ref next); break; case Gdk.Key.End: OnKeyEnd(ref cur, ref next); break; case Gdk.Key.Insert: OnKeyInsert(); break; case Gdk.Key.Tab: OnKeyTab(); // cycling through the areas may change the current cursor digit // (note however that we don't want to call EvaluateSelection()->SetCursor() // because that will reset the digit of all areas. So we just update // selStartPos.Digit here and set specialKey = true to avoid calling SetCursor()...) selStartPos.Digit = dvDisplay.Layout.AreaGroup.CursorDigit; specialKey = true; break; case Gdk.Key.BackSpace: OnKeyBackspace(); return; // OnKeyBackspace() handles drawing default: OnKeyDefault(e, ref cur, ref next, out specialKey); break; } // end switch() //System.Console.WriteLine("Current: {0},{1},{2} Next: {3},{4},{5}", cur.First, cur.Second, cur.Digit, next.First, next.Second, next.Digit); // if just a special key was pressed (eg shift, ctrl, tab or a digit the area doesn't understand don't do anything) if (specialKey) return; if (shiftPressed) { next.Digit = 0; if (selStartPos.First == selStartPos.Second) selStartPos.First--; selEndPos = next; } else { selEndPos = next; selStartPos = next; } //System.Console.WriteLine("Start: {0},{1},{2} End: {3},{4},{5}", selStartPos.First, selStartPos.Second, selStartPos.Digit, selEndPos.First, selEndPos.Second, selEndPos.Digit); EvaluateSelection(okp_showType); } ///Handle key releases internal void OnKeyRelease (object o, KeyReleaseEventArgs args) { // do nothing } internal void OnMouseWheel(object o, ScrollEventArgs args) { Gdk.EventScroll e = args.Event; if (e.Direction == Gdk.ScrollDirection.Down) { double newValue = dvDisplay.VScroll.Value + dvDisplay.VScroll.Adjustment.StepIncrement; if (newValue <= dvDisplay.VScroll.Adjustment.Upper - dvDisplay.VScroll.Adjustment.PageSize) dvDisplay.VScroll.Value = newValue; else dvDisplay.VScroll.Value = dvDisplay.VScroll.Adjustment.Upper - dvDisplay.VScroll.Adjustment.PageSize; } else if (e.Direction == Gdk.ScrollDirection.Up) { double newValue = dvDisplay.VScroll.Value - dvDisplay.VScroll.Adjustment.StepIncrement; if (newValue >= dvDisplay.VScroll.Adjustment.Lower) dvDisplay.VScroll.Value = newValue; else dvDisplay.VScroll.Value = dvDisplay.VScroll.Adjustment.Lower; } } /// /// Handle DataView focus gain /// internal void OnFocusInEvent (object o, FocusInEventArgs args) { foreach(Area a in dvDisplay.Layout.AreaGroup.Areas) a.IsActive = true; dataView.FireFocusChangedEvent(); } /// /// Handle DataView focus loss /// internal void OnFocusOutEvent (object o, FocusOutEventArgs args) { foreach(Area a in dvDisplay.Layout.AreaGroup.Areas) a.IsActive = false; dataView.FireFocusChangedEvent(); } // // Key Handlers, called by OnKeyPress // void OnKeyUp(ref Position cur, ref Position next) { long offset = cur.Second; offset -= okp_bpr; if (offset < 0) { next.First = cur.Second; next.Second = cur.Second; } else { next.First = offset - 1; next.Second = offset; } next.Digit = cur.Digit; } void OnKeyDown(ref Position cur, ref Position next) { long offset = cur.Second; offset += okp_bpr; if (offset > dataView.Buffer.Size) { next.First = dataView.Buffer.Size; next.Second = dataView.Buffer.Size; } else { next.First = offset - 1; next.Second = offset; } next.Digit = cur.Digit; } void OnKeyLeft(ref Position cur, ref Position next) { long offset = cur.Second; int digit = cur.Digit; digit--; if (digit < 0) { offset--; digit = okp_dpb - 1; } if (offset < 0) { offset = 0; digit = 0; } next.First = offset - 1; next.Second = offset; next.Digit = digit; } void OnKeyRight(ref Position cur, ref Position next) { long offset = cur.Second; int digit = cur.Digit; digit++; if (digit >= okp_dpb) { offset++; digit = 0; } if (offset > dataView.Buffer.Size) { offset = dataView.Buffer.Size; digit = okp_dpb - 1; } next.First = offset - 1; next.Second = offset; next.Digit = digit; } void OnKeyPageUp(ref Position cur, ref Position next) { long offset = cur.Second; int digit = cur.Digit; offset -= okp_bpr * (int)dvDisplay.VScroll.Adjustment.PageIncrement; if (offset < 0) { offset = 0; //digit = 0; } okp_showType = DataViewDisplay.ShowType.Cursor; next.First = offset; next.Second = offset; next.Digit = digit; } void OnKeyPageDown(ref Position cur, ref Position next) { long offset = cur.Second; int digit = cur.Digit; offset += okp_bpr * (int)dvDisplay.VScroll.Adjustment.PageIncrement; if (offset > dataView.Buffer.Size) { offset = dataView.Buffer.Size; //digit = 0; } okp_showType = DataViewDisplay.ShowType.Cursor; next.First = offset; next.Second = offset; next.Digit = digit; } void OnKeyHome(ref Position cur, ref Position next) { next.First = 0; next.Second = 0; next.Digit = 0; okp_showType = DataViewDisplay.ShowType.Start; } void OnKeyEnd(ref Position cur, ref Position next) { next.First = dataView.Buffer.Size; next.Second = dataView.Buffer.Size; next.Digit = 0; okp_showType = DataViewDisplay.ShowType.End; } void OnKeyInsert() { dataView.Overwrite = !dataView.Overwrite; } void OnKeyTab() { dvDisplay.Layout.AreaGroup.CycleFocus(); } void OnKeyBackspace() { // move one position backwards and delete dataView.DeleteBackspace(); } void OnKeyDefault(Gdk.EventKey e, ref Position cur, ref Position next, out bool specialKey) { if (!dataView.Buffer.ModifyAllowed) { specialKey = true; return; } // if the buffer isn't resizable, ignore non-overwriting keypresses if (!dataView.Buffer.IsResizable && !dataView.Overwrite) { specialKey = true; return; } if (dataView.Selection.IsEmpty()) { if (imContext.FilterKeypress(e) && okp_focusArea.HandleKey(e.Key, dataView.Overwrite) == true) { OnKeyRight(ref cur, ref next); dataView.CursorUndoDeque.AddFront(new CursorState(cur.Second, cur.Digit, next.Second, next.Digit)); dataView.CursorRedoDeque.Clear(); selStartPos = selEndPos = next; specialKey = false; } else specialKey = true; } else { dataView.Buffer.BeginActionChaining(); // Insert the new data and delete the old if (imContext.FilterKeypress(e) && okp_focusArea.HandleKey(e.Key, false) == true) { Util.Range curSel = dataView.Selection; long curOffset = dataView.CursorOffset; // move cursor to the right OnKeyRight(ref cur, ref next); next.First = next.Second = curSel.Start; selEndPos = selStartPos = next; // the new data could have been inserted either just after the end // or at the beginning of the selection. Handle each case // and delete the old data. if (curOffset > curSel.End) { // new data just after end dataView.Delete(); } else { // curOffset == curSel.Start, new data at the beginning // shift selection one position to the right dataView.SetSelection(curSel.Start + 1, curSel.End + 1); dataView.Delete(); } specialKey = false; } else { specialKey = true; } dataView.Buffer.EndActionChaining(); } // any other key pass it to focused area // if area handled it move one position right } public void Cleanup() { okp_focusArea = null; dataView = null; dvDisplay = null; } } // end DataViewControl } //end namespace bless-0.6.3/src/gui/DataViewDisplay.cs000066400000000000000000000316031374060072200175700ustar00rootroot00000000000000// created on 1/11/2005 at 9:43 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using Gtk; using Bless.Buffers; using Bless.Gui.Areas; using Bless.Gui.Drawers; using Bless.Util; namespace Bless.Gui { ///A widget that displays data from a buffer public class DataViewDisplay : Gtk.VBox { Layout layout; Gtk.HBox hbox; Gtk.DrawingArea drawingArea; //static Gtk.DrawingArea drawingArea=new Gtk.DrawingArea(); Gtk.VScrollbar vscroll; Gtk.HBox fileChangedBar; bool widgetRealized; DataViewControl dvControl; DataView dataView; public enum ShowType { Closest, Start, End, Cursor } public DataView View { get { return dataView;} } public DataViewControl Control { set { DisconnectFromControl(); // connect new control dvControl = value; ConnectToControl(); } get { return dvControl; } } public Layout Layout { get { return layout; } set { // temporarily save previous layout Layout prevLayout = layout; // dispose Area pixmaps layout.DisposePixmaps(); // set new layout layout = value; // set buffer layout.AreaGroup.Buffer = dataView.Buffer; if (widgetRealized) { layout.Realize(drawingArea); Gdk.Rectangle alloc = drawingArea.Allocation; Resize(alloc.Width, alloc.Height); long prevOffset = 0; // Setup new areas according to the old ones if (prevLayout != null && prevLayout.AreaGroup.Areas.Count > 0) { layout.AreaGroup.SetCursor(prevLayout.AreaGroup.CursorOffset, 0); layout.AreaGroup.Selection = prevLayout.AreaGroup.Selection; } else { layout.AreaGroup.SetCursor(0, 0); } // make sure cursor is visible MakeOffsetVisible(prevOffset, ShowType.Closest); } } } internal Gtk.VScrollbar VScroll { get { return vscroll; } } public new bool HasFocus { get { return drawingArea.HasFocus; } set { drawingArea.HasFocus = value; } } ///Create a DataViewDisplay public DataViewDisplay(DataView dv) { dataView = dv; // load the default layout from the data directory layout = new Layout(FileResourcePath.GetDataPath("bless-default.layout")); // initialize scrollbar Gtk.Adjustment adj = new Gtk.Adjustment(0.0, 0.0, 1.0, 1.0, 10.0, 0.0); vscroll = new Gtk.VScrollbar(adj); adj.ValueChanged += OnScrolled; // initialize drawing area drawingArea = new Gtk.DrawingArea(); drawingArea.Realized += OnRealized; drawingArea.ExposeEvent += OnExposed; drawingArea.ConfigureEvent += OnConfigured; drawingArea.ModifyBg(StateType.Normal, new Gdk.Color(0xff, 0xff, 0xff)); // add events that we want to handle drawingArea.AddEvents((int)Gdk.EventMask.ButtonPressMask); drawingArea.AddEvents((int)Gdk.EventMask.ButtonReleaseMask); drawingArea.AddEvents((int)Gdk.EventMask.PointerMotionMask); drawingArea.AddEvents((int)Gdk.EventMask.PointerMotionHintMask); drawingArea.AddEvents((int)Gdk.EventMask.KeyPressMask); drawingArea.AddEvents((int)Gdk.EventMask.KeyReleaseMask); drawingArea.CanFocus = true; // needed to catch key events hbox = new Gtk.HBox(); hbox.PackStart(drawingArea , true, true, 0); hbox.PackStart(vscroll , false, false, 0); this.PackStart(hbox); } ///Force a complete redraw of the view public void Redraw() { if (!widgetRealized) return; Gdk.Rectangle alloc = drawingArea.Allocation; Resize(alloc.Width, alloc.Height); layout.AreaGroup.Invalidate(); drawingArea.QueueDraw(); } /// /// Find the number of bytes per row in order /// to best utilize the available space and /// keep all areas synchronized. /// private int FindBestBpr(int width) { int n = 1; // current bpr int bestBpr = -1; // best bpr so far int swBest = 0; // width of best bpr so far // try all values for n, from 0 upwards, // until the width for a given n exceeds // the available or the fixed bpr of an // area is exceeded while (true) { int sw = 0; // total width with current bpr bool breaksGrouping = false; bool breaksFixed = false; foreach(Area a in layout.AreaGroup.Areas) { int w = a.CalcWidth(n, false); // if this number of bpr is not acceptable if (w == -1) { if (a.FixedBytesPerRow != -1 && n > a.FixedBytesPerRow ) breaksFixed = true; else breaksGrouping = true; break; } sw += w; } // If current bpr breaks a fixed size area // stop searching and use the last bpr value // that did't break it. // If there isn't such an area, keep searching if (breaksFixed && bestBpr != -1) break; // if current bpr breaks grouping, skip it if (!breaksGrouping) { bool shouldBreak = false; // stop searching if available width is exceeded // or last best width value equals current one if (sw > width || sw == swBest) shouldBreak = true; // if we should break, but haven't found a suitable // width yet, mark the current width as best so far // even if it violates available width constraints. if ((shouldBreak && bestBpr == -1) || (!shouldBreak)) { // keep best bpr so far bestBpr = n; swBest = sw; } if (shouldBreak) break; } n++; } return bestBpr; } ///Benchmark the rendering public void Benchmark() { System.DateTime t1; System.DateTime t2; int sum = 0; Gdk.Window win = drawingArea.GdkWindow; Gdk.Rectangle alloc = drawingArea.Allocation; Gdk.Rectangle rect1 = new Gdk.Rectangle(0, 0, alloc.Width, alloc.Height); for (int i = 0; i < 100; i++) { t1 = System.DateTime.Now; win.BeginPaintRect(rect1); layout.AreaGroup.Render(true); win.EndPaint(); t2 = System.DateTime.Now; sum += (t2 - t1).Milliseconds; } Gdk.Rectangle rect = drawingArea.Allocation; Console.WriteLine("100 render screen ({0},{1}): {2} ms", rect.Width, rect.Height, sum / 100); } private void SetupScrollbarRange() { if (layout.AreaGroup.Areas.Count <= 0) return; long bpr = ((Area)layout.AreaGroup.Areas[0]).BytesPerRow; long nrows = ((dataView.Buffer.Size + 1) / bpr); // +1 because of append cursor position if (nrows < vscroll.Adjustment.PageSize) { vscroll.Value = 0; // set adjustment manually instead of using SetRange // because gtk+ complains if low==high in SetRange() vscroll.Adjustment.Lower = 0; vscroll.Adjustment.Upper = nrows; vscroll.Hide(); } else if ((dataView.Buffer.Size + 1) % bpr == 0) { vscroll.SetRange(0, nrows); vscroll.Show(); } else { vscroll.SetRange(0, nrows + 1); vscroll.Show(); } } ///Handles window resizing private void Resize(int winWidth, int winHeight) { // find bytes per row... int bpr = FindBestBpr(winWidth); // Ensure our offset is always aligned with bpr if (bpr > 0) layout.AreaGroup.Offset = (layout.AreaGroup.Offset / bpr) * bpr; // configure areas int s = 0; int fontHeight = winHeight; foreach(Area a in layout.AreaGroup.Areas) { a.Height = winHeight; a.Width = a.CalcWidth(bpr, true); a.X = s; a.BytesPerRow = bpr; s += a.Width; if (a.Drawer.Height < fontHeight) { fontHeight = a.Drawer.Height; } } // configure scrollbar vscroll.Adjustment.PageSize = (winHeight / fontHeight); vscroll.SetIncrements(3, vscroll.Adjustment.PageSize - 1); // decide whether the scrollbar is visible // and its range if (bpr == 0) { // this can cause eternal loop! // because hiding the scrollbar changes the // area and causes a reconfigure which may // show it again, and so on //vscroll.Hide(); } else SetupScrollbarRange(); layout.AreaGroup.Invalidate(); } ///Handle the Configure Event void OnConfigured (object o, ConfigureEventArgs args) { if (widgetRealized == false) return; Gdk.EventConfigure conf = args.Event; Resize(conf.Width, conf.Height); // make sure the current offset is visible MakeOffsetVisible(dataView.Offset, ShowType.Start); } ///Handle the Expose Event void OnExposed (object o, ExposeEventArgs args) { layout.AreaGroup.Render(true); } ///Handle the Realized Event void OnRealized (object o, EventArgs args) { // Create some default areas layout.Realize(drawingArea); widgetRealized = true; // now we can configure properly Gdk.Rectangle alloc = ((Widget)o).Allocation; Resize(alloc.Width, alloc.Height); } ///Handle scrolling void OnScrolled (object o, EventArgs args) { int bpr = 0; if (layout.AreaGroup.Areas.Count > 0) bpr = ((Area)layout.AreaGroup.Areas[0]).BytesPerRow; long offset = (long)vscroll.Adjustment.Value * bpr; layout.AreaGroup.Offset = offset; } ///Scroll the view so that offset is visible public void MakeOffsetVisible(long offset, ShowType type) { if (layout.AreaGroup.Areas.Count <= 0) return; int bpr = ((Area)layout.AreaGroup.Areas[0]).BytesPerRow; if (bpr == 0) return ; long curOffset = layout.AreaGroup.Offset; int h = ((Area)layout.AreaGroup.Areas[0]).Height; Drawer font = ((Area)layout.AreaGroup.Areas[0]).Drawer; int nrows = h / font.Height; long curOffsetRow = curOffset / bpr; long curOffsetEndRow = curOffsetRow + nrows - 1; long offsetRow = offset / bpr; //System.Console.WriteLine("curOffRow: {0} curOffEndRow: {1} offRow: {2}", // curOffsetRow, curOffsetEndRow, offsetRow); if (type == ShowType.Closest) { // if already visible do nothing //if (offsetRow >= curOffsetRow && offsetRow <= curOffsetEndRow) // ; if (curOffsetRow > offsetRow) type = ShowType.Start; else if (curOffsetEndRow < offsetRow) type = ShowType.End; } // Make sure scrollbar range is updated. // We need to call this here because // a buffer change does not immediately // update the range (eg callback goes through GLib.Idle) // and a call to MakeOffsetVisible before // the update will not behave correctly. // eg see DataView.Paste() SetupScrollbarRange(); if (type == ShowType.Cursor) { long cursorRow = layout.AreaGroup.CursorOffset / bpr; int diff = (int)(cursorRow - curOffsetRow); if (diff <= nrows && diff >= 0) vscroll.Value = offsetRow - diff; // else if diff is outside of a full screen range... else if (diff > nrows) type = ShowType.End; else if (diff < 0) type = ShowType.Start; } if (type == ShowType.Start) { vscroll.Value = offsetRow; } else if (type == ShowType.End) { if (offsetRow - nrows >= 0) vscroll.Value = offsetRow - nrows + 1; else vscroll.Value = 0; } } /// /// Show a warning that the file has been changed /// outside of the respective DataView /// public void ShowFileChangedBar() { if (fileChangedBar == null) { fileChangedBar = new FileChangedBar(this.View); this.PackStart(fileChangedBar, false, false, 0); } this.ReorderChild(fileChangedBar, 0); fileChangedBar.ShowAll(); } public void Cleanup() { layout.DisposePixmaps(); layout = null; dataView = null; dvControl = null; } public void GrabKeyboardFocus() { if (!drawingArea.HasFocus) drawingArea.GrabFocus(); } private void ConnectToControl() { if (dvControl == null) return; drawingArea.ButtonPressEvent += dvControl.OnButtonPress; drawingArea.ButtonReleaseEvent += dvControl.OnButtonRelease; drawingArea.MotionNotifyEvent += dvControl.OnMotionNotify; drawingArea.KeyPressEvent += dvControl.OnKeyPress; drawingArea.KeyReleaseEvent += dvControl.OnKeyRelease; drawingArea.ScrollEvent += dvControl.OnMouseWheel; drawingArea.FocusInEvent += dvControl.OnFocusInEvent; drawingArea.FocusOutEvent += dvControl.OnFocusOutEvent; } private void DisconnectFromControl() { // disconnect previous control if (dvControl == null) return; drawingArea.ButtonPressEvent -= dvControl.OnButtonPress; drawingArea.ButtonReleaseEvent -= dvControl.OnButtonRelease; drawingArea.MotionNotifyEvent -= dvControl.OnMotionNotify; drawingArea.KeyPressEvent -= dvControl.OnKeyPress; drawingArea.KeyReleaseEvent -= dvControl.OnKeyRelease; drawingArea.ScrollEvent -= dvControl.OnMouseWheel; drawingArea.FocusInEvent -= dvControl.OnFocusInEvent; drawingArea.FocusOutEvent -= dvControl.OnFocusOutEvent; } }// end DataView }//namespace bless-0.6.3/src/gui/FileChangedBar.cs000066400000000000000000000051411374060072200173120ustar00rootroot00000000000000// created on 4/29/2005 at 1:36 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using Gtk; using Bless.Gui.Dialogs; using Mono.Unix; namespace Bless.Gui { /// /// A widget that notifies the user that the file has changed /// and prompts them to reload or ignore. /// public class FileChangedBar : Gtk.HBox { DataView dataView; public FileChangedBar(DataView dv) { dataView = dv; this.BorderWidth = 3; Gtk.Image img = new Gtk.Image(Gtk.Stock.DialogWarning, Gtk.IconSize.SmallToolbar); Gtk.Label label = new Gtk.Label(Catalog.GetString("This file has been changed on disk. You may choose to ignore the changes but reloading is the only safe option.")); label.LineWrap = true; label.Wrap = true; Gtk.Button buttonIgnore = new Gtk.Button(Catalog.GetString("Ignore")); buttonIgnore.Clicked += OnFileChangedIgnore; Gtk.Button buttonReload = new Gtk.Button(Catalog.GetString("Reload")); buttonReload.Clicked += OnFileChangedReload; this.PackStart(img, false, false, 4); this.PackStart(label, false, false, 10); this.PackStart(buttonIgnore, false, false, 10); this.PackStart(buttonReload, false, false, 10); } void OnFileChangedIgnore(object o, EventArgs args) { WarningAlert wa = new WarningAlert(Catalog.GetString("Are you sure you want to ignore the changes?"), Catalog.GetString("Due to the way Bless handles files, ignoring these changes may corrupt your data."), null); ResponseType res = (ResponseType)wa.Run(); wa.Destroy(); if (res == ResponseType.Ok) { this.Visible = false; dataView.Notification = false; dataView.Buffer.FileOperationsAllowed = true; } } void OnFileChangedReload(object o, EventArgs args) { this.Visible = false; dataView.Buffer.FileOperationsAllowed = true; dataView.Notification = false; dataView.Revert(); } } } // end namespace bless-0.6.3/src/gui/FileService.cs000066400000000000000000000357711374060072200167500ustar00rootroot00000000000000// created on 4/29/2006 at 3:37 PM /* * Copyright (c) 2006, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using Gtk; using Bless.Buffers; using Bless.Gui.Dialogs; using Bless.Tools; using Bless.Util; using System; using System.IO; using System.Collections; using Mono.Unix; namespace Bless.Gui { public class FileService { DataBook dataBook; Window mainWindow; public FileService(DataBook db, Window mw) { dataBook = db; mainWindow = mw; } /// /// Create and setup a DataView /// public DataView CreateDataView(ByteBuffer bb) { DataView dv = new DataView(); string layoutFile = string.Empty; // try to load default (from user preferences) layout file try { layoutFile = Preferences.Instance["Default.Layout.File"]; string useCurrent = Preferences.Instance["Default.Layout.UseCurrent"]; if (useCurrent == "True" && dataBook.NPages > 0) { DataViewDisplay dvd = (DataViewDisplay)dataBook.CurrentPageWidget; layoutFile = dvd.Layout.FilePath; } if (layoutFile != string.Empty) dv.Display.Layout = new Bless.Gui.Layout(layoutFile); } catch (Exception ex) { string msg = string.Format(Catalog.GetString("Error loading layout '{0}'. Loading default layout instead."), layoutFile); ErrorAlert ea = new ErrorAlert(msg, ex.Message , mainWindow); ea.Run(); ea.Destroy(); } if (Preferences.Instance["Default.EditMode"] == "Insert") dv.Overwrite = false; else if (Preferences.Instance["Default.EditMode"] == "Overwrite") dv.Overwrite = true; dv.Buffer = bb; return dv; } ///If file has changed ask whether to save it. /// Returns true if file saved or the user doesn't want to save it. private bool AskForSaveIfFileChanged(DataView dv) { ByteBuffer bb = dv.Buffer; if (bb == null) return true; if (bb.HasChanged) { SaveConfirmationAlert sca = new SaveConfirmationAlert(bb.Filename, mainWindow); ResponseType res = (ResponseType)sca.Run(); sca.Destroy(); if (res == ResponseType.Ok) { return SaveFile(dv, null, false, true); } else if (res == ResponseType.No){ return true; } else /*if (res==ResponseType.Cancel)*/ return false; } return true; } ///If any file has changed ask whether to save it. /// Returns true if all changed files are saved or the user doesn't want to save them. private bool AskForSaveIfFilesChanged() { ArrayList list = new ArrayList(); // create a list with the changed files int i = 0; foreach (DataViewDisplay dv in dataBook.Children) { ByteBuffer bb = dv.View.Buffer; if (bb.HasChanged) list.Add(new SaveFileItem(true, bb.Filename, i)); i++; } if (list.Count == 0) return true; // special handling if only one file changed if (list.Count == 1) { int page = ((SaveFileItem)list[0]).Page; // make the page active dataBook.Page = page; DataView dv = ((DataViewDisplay)dataBook.GetNthPage(page)).View; return AskForSaveIfFileChanged(dv); } // show the confirmation alert SaveFileItem[] array = (SaveFileItem[])list.ToArray(typeof(SaveFileItem)); SaveConfirmationMultiAlert sca = new SaveConfirmationMultiAlert(array, mainWindow); ResponseType res = (ResponseType)sca.Run(); sca.Destroy(); // handle responses if (res == ResponseType.Ok) { bool allSaved = true; // save the files the user specified foreach(SaveFileItem item in array) { if (item.Save == true) { DataView dv = ((DataViewDisplay)dataBook.GetNthPage(item.Page)).View; // make page active dataBook.Page = item.Page; // try to save the file if (SaveFile(dv, null, false, true) == false) allSaved = false; else { //UpdateTabLabel(dv); //UpdateWindowTitle(dv); } } } return allSaved; } else if (res == ResponseType.No){ return true; } else /*if (res==ResponseType.Cancel)*/ return false; } /// /// Create new file /// public ByteBuffer NewFile() { ByteBuffer bb = new ByteBuffer(); bb.UseGLibIdle = true; if (Preferences.Instance["ByteBuffer.TempDir"] != "") bb.TempDir = Preferences.Instance["ByteBuffer.TempDir"]; return bb; } /// /// Try to open the file as a ByteBuffer /// public ByteBuffer OpenFile(string filename) { Uri uri = null; // first try filename as a URI try { uri = new Uri(filename); } catch { } // if filename is a valid URI if (uri != null) { // try to open the URI as an unescaped path try { return OpenFileInternal(uri.LocalPath, false); } catch (FileNotFoundException) { } // try to open the URI as an escaped path try { return OpenFileInternal(uri.AbsolutePath, false); } catch (FileNotFoundException) { } } // filename is not a valid URI... (eg the path contains invalid URI characters like ':') // try to expand it as a local path try { string fullPath = Path.GetFullPath(filename); return OpenFileInternal(fullPath, true); } catch (Exception ex) { string msg = string.Format(Catalog.GetString("Error opening file '{0}'"), filename); ErrorAlert ea = new ErrorAlert(msg, ex.Message, mainWindow); ea.Run(); ea.Destroy(); return null; } } private ByteBuffer OpenFileInternal(string fullPath, bool handleFileNotFound) { try { ByteBuffer bb = ByteBuffer.FromFile(fullPath); bb.UseGLibIdle = true; if (Preferences.Instance["ByteBuffer.TempDir"] != "") bb.TempDir = Preferences.Instance["ByteBuffer.TempDir"]; string msg = string.Format(Catalog.GetString("Loaded file '{0}'"), fullPath); Services.UI.Info.DisplayMessage(msg); History.Instance.Add(fullPath); return bb; } catch (UnauthorizedAccessException) { string msg = string.Format(Catalog.GetString("Error opening file '{0}'"), fullPath); ErrorAlert ea = new ErrorAlert(msg, Catalog.GetString("You do not have read permissions for the file you requested."), mainWindow); ea.Run(); ea.Destroy(); } catch (System.IO.FileNotFoundException) { if (handleFileNotFound == false) throw; string msg = string.Format(Catalog.GetString("Error opening file '{0}'"), fullPath); ErrorAlert ea = new ErrorAlert(msg, Catalog.GetString("The file you requested does not exist."), mainWindow); ea.Run(); ea.Destroy(); } catch (System.IO.IOException ex) { string msg = string.Format(Catalog.GetString("Error opening file '{0}'"), fullPath); ErrorAlert ea = new ErrorAlert(msg, ex.Message, mainWindow); ea.Run(); ea.Destroy(); } catch (System.ArgumentException ex) { string msg = string.Format(Catalog.GetString("Error opening file '{0}'"), fullPath); ErrorAlert ea = new ErrorAlert(msg, ex.Message, mainWindow); ea.Run(); ea.Destroy(); } catch (System.NotSupportedException ex) { string msg = string.Format(Catalog.GetString("Error opening file '{0}'"), fullPath); ErrorAlert ea = new ErrorAlert(msg, ex.Message, mainWindow); ea.Run(); ea.Destroy(); } return null; } /// /// Manage high-level file saving procedures (eg confirm file overwrites, get filenames etc) /// public bool SaveFile(DataView dv, string filename, bool forceSaveAs, bool synchronous) { ByteBuffer bb = dv.Buffer; if (!dv.Buffer.FileOperationsAllowed) { return false; } // if a filename is given, save the file under the specified filename if (!forceSaveAs && filename != null) return SaveFileInternal(dv, filename, synchronous); // if a filename is not given but buffer // has a file associated with it, save it under the same filename if (!forceSaveAs && filename == null && bb.HasFile == true && bb.Filename.Length != 0) return SaveFileInternal(dv, bb.Filename, synchronous); // otherwise prompt user for a name Gtk.FileChooserDialog fs = new Gtk.FileChooserDialog(Catalog.GetString("Save File As"), mainWindow, FileChooserAction.Save, Gtk.Stock.Cancel, ResponseType.Cancel, Gtk.Stock.Save, ResponseType.Accept); bool done = false; bool fileSaved = true; do { ResponseType response = (ResponseType)fs.Run(); fs.Hide(); if (response == ResponseType.Accept) { // check to see whether file exists and prompt user to confirm if (File.Exists(fs.Filename)) { FileOverwriteAlert ea = new FileOverwriteAlert(fs.Filename, mainWindow); ResponseType response1 = (ResponseType)ea.Run(); ea.Destroy(); if (response1 == ResponseType.Ok) { fileSaved = SaveFileInternal(dv, fs.Filename, synchronous); done = true; } else done = false; } else{ // !File.Exists(fs.Filename) fileSaved = SaveFileInternal(dv, fs.Filename, synchronous); done = true; } } else { // response!=ResponseType.OK done = true; fileSaved = false; } } while (!done); fs.Destroy(); //UpdateRevert(dv); return fileSaved; } /// /// Manage low-level file saving procedures /// private bool SaveFileInternal(DataView dv, string filename, bool synchronous) { ByteBuffer bb = dv.Buffer; string fullPath = null; // get the full path try { fullPath = Path.GetFullPath(filename); } catch (Exception ex) { string msg = string.Format(Catalog.GetString("Error saving file '{0}'"), filename); ErrorAlert ea = new ErrorAlert(msg, ex.Message, mainWindow); ea.Run(); ea.Destroy(); } // if we can't get full path, return if (fullPath == null) return false; try { string msg; if (fullPath != bb.Filename) msg = string.Format(Catalog.GetString("Saving file '{0}' as '{1}'"), bb.Filename, fullPath); else msg = string.Format(Catalog.GetString("Saving file '{0}'"), bb.Filename); Services.UI.Info.DisplayMessage(msg + "..."); IAsyncResult ar; // Decide whether to save or save as if (fullPath != bb.Filename) ar = bb.BeginSaveAs(fullPath, Services.UI.Progress.NewCallback(), new AsyncCallback(SaveFileAsyncCallback)); else ar = bb.BeginSave(Services.UI.Progress.NewCallback(), new AsyncCallback(SaveFileAsyncCallback)); // if save is synchronous wait for save to finish if (synchronous) { // while waiting update the gui while (ar.AsyncWaitHandle.WaitOne(50, true) == false) { while ( Application.EventsPending() ) { Application.RunIteration(); } } // find out if save succeeded SaveAsOperation bbs = (SaveAsOperation)ar.AsyncState; if (bbs.Result != SaveAsOperation.OperationResult.Finished) return false; // add to history History.Instance.Add(bbs.SavePath); return true; } } catch (IOException ex) { string file; if (fullPath != bb.Filename) file = fullPath; else file = bb.Filename; string msg = string.Format(Catalog.GetString("Error saving file '{0}'"), file); ErrorAlert ea = new ErrorAlert(msg, ex.Message, mainWindow); ea.Run(); ea.Destroy(); msg = string.Format(Catalog.GetString("The file '{0}' has NOT been saved"), file); Services.UI.Info.DisplayMessage(msg); } return false; } /// /// Callback to call when a save operation has finished /// void SaveFileAsyncCallback(IAsyncResult ar) { ISaveState ss = (ISaveState)ar.AsyncState; if (ss.Result == ThreadedAsyncOperation.OperationResult.Finished) { // save went ok string msg; if (ss.SavePath != ss.Buffer.Filename) msg = string.Format(Catalog.GetString("The file has been saved as '{0}'"), ss.SavePath); else msg = string.Format(Catalog.GetString("The file '{0}' has been saved"), ss.SavePath); Services.UI.Info.DisplayMessage(msg); // add to history History.Instance.Add(ss.SavePath); return; } else if (ss.Result == ThreadedAsyncOperation.OperationResult.Cancelled) { // save cancelled } else if (ss.Result == ThreadedAsyncOperation.OperationResult.CaughtException) { // * UnauthorizedAccessException // * System.ArgumentException // * System.IO.IOException string msg = string.Format(Catalog.GetString("Error saving file '{0}'"), ss.SavePath); ErrorAlert ea = new ErrorAlert(msg, ss.ThreadException.Message, mainWindow); ea.Run(); ea.Destroy(); } { string msg = string.Format(Catalog.GetString("The file '{0}' has NOT been saved"), ss.SavePath); Services.UI.Info.DisplayMessage(msg); } } public void CloseFile(DataView dv) { if (!dv.Buffer.FileOperationsAllowed) return; // if user decides not to close after all if (AskForSaveIfFileChanged(dv) == false) return; dataBook.RemoveView(dv); // promptly free resources memory (eg pixmaps) dv.Buffer.CloseFile(); dv.Cleanup(); // Make sure the new current DataView has the focus DataViewDisplay dvd = (DataViewDisplay)dataBook.CurrentPageWidget; if (dvd != null) dvd.GrabKeyboardFocus(); else { // there is no dataview left, // update title and statusbars mainWindow.Title = "Bless - Gtk# Hex Editor"; Services.UI.Info.ClearMessage(); } } /// /// Try to quit. Ask user to save files before quitting and /// save the current session. /// public void TryQuit() { if (AskForSaveIfFilesChanged()) { string blessConfDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "bless"); try { Services.Session.Save(Path.Combine(blessConfDir, "last.session")); History.Instance.Save(Path.Combine(blessConfDir, "history.xml")); } catch (Exception ex) { System.Console.WriteLine(ex.Message); } Application.Quit (); } } /// /// Load the files specified /// public void LoadFiles(string[] files) { // should we replace the current page or create a new one? bool replaceCurrentPage = dataBook.CanReplacePage(dataBook.CurrentPage); foreach(string file in files) { // try to open the file ByteBuffer bb = OpenFile(file); // if open was successful if (bb != null) { DataView newDv = CreateDataView(bb); if (replaceCurrentPage) { // replace current page DataView dv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; dataBook.ReplaceView(dv, newDv, new CloseViewDelegate(CloseFile), Path.GetFileName(bb.Filename)); // promptly free resources memory (eg pixmaps) dv.Buffer.CloseFile(); dv.Cleanup(); replaceCurrentPage = false; } else { // create new page // create and setup a DataView dataBook.AppendView(newDv, new CloseViewDelegate(CloseFile), Path.GetFileName(bb.Filename)); } } } } } } bless-0.6.3/src/gui/Layout.cs000066400000000000000000000061511374060072200160130ustar00rootroot00000000000000// Configured on 6/26/2004 at 1:42 PM /* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System.Collections.Generic; using System; using System.Xml; using System.IO; using Gtk; using Bless.Gui.Areas; using Bless.Gui.Drawers; using Bless.Buffers; namespace Bless.Gui { /// /// A class that keeps information about how the data will be /// placed and shown on screen. /// public class Layout { AreaGroup areaGroup; XmlDocument layoutDoc; Drawer font; string filePath; DateTime timeStamp; public AreaGroup AreaGroup { get {return areaGroup;} } public string FilePath { get { return filePath; } } public DateTime TimeStamp { get { return timeStamp; } } public Layout() { areaGroup = new AreaGroup(); layoutDoc = new XmlDocument(); filePath = null; } public Layout(string name): this() { Load(name); } ///Loads the layout from a file containing xml public void Load(string name) { using (XmlReader xmlReader = XmlReader.Create(name)) { layoutDoc.Load(xmlReader); Configure(); filePath = name; timeStamp = File.GetLastWriteTime(name); } } ///Loads the layout from string containing xml public void LoadXml(string xml) { layoutDoc.LoadXml(xml); } /// /// Create and configure the areas, as defined in the layout file. /// void Configure() { XmlNodeList areaList = layoutDoc.GetElementsByTagName("area"); foreach(XmlNode areaNode in areaList) { XmlAttributeCollection attrColl = areaNode.Attributes; string type = attrColl["type"].Value; Area area = Area.Factory(type, areaGroup); if (area == null) continue; areaGroup.Areas.Add(area); area.Configure(areaNode); } // give the focus to the first applicable area foreach(Area a in areaGroup.Areas) { if (a.Type != "offset" && a.Type != "separator") { a.HasCursorFocus = true; areaGroup.FocusedArea = a; break; } } // reset cursor areaGroup.SetCursor(0, 0); } /// /// Realizes the areas. /// public void Realize(Gtk.DrawingArea da) { areaGroup.DrawingArea = da; foreach(Area a in areaGroup.Areas) a.Realize(); } ///Dispose the pixmap resources used by the layout public void DisposePixmaps() { foreach(Area a in areaGroup.Areas) { a.DisposePixmaps(); } } } }//namespace bless-0.6.3/src/gui/MainWindow.cs000066400000000000000000000314361374060072200166160ustar00rootroot00000000000000// project created on 6/3/2004 at 8:34 PM /* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.Collections; using System.Threading; using System.IO; using Gtk; using Bless.Buffers; using Bless.Gui; using Bless.Gui.Areas; using Bless.Gui.Dialogs; using Bless.Tools.Find; using Bless.Tools; using Bless.Util; using Bless.Plugins; using Mono.Unix; public class BlessMain { [Gtk.Builder.Object] Gtk.HBox DataViewBox; [Gtk.Builder.Object] Gtk.Window MainWindow; [Gtk.Builder.Object] Gtk.VBox MainVBox; const string uiXml = "" + " " + " " + " " + " " + " " + " " + " " + " " + "" + "" + " " + " " + " " + " " + " " + ""; ActionEntry[] actionEntries; UIManager uiManager; Gtk.AccelGroup editAccelGroup; // the group of accelerators for the edit menu DataBook dataBook; // the kinds of MIME type targets we are accepting static TargetEntry[] dropTargets = new TargetEntry[]{ new TargetEntry("text/uri-list", 0, 0) }; public static void Main (string[] args) { new BlessMain(args); } public BlessMain (string[] args) { Application.Init(); // Catalog.Init(ConfigureDefines.GETTEXT_PACKAGE, ConfigureDefines.LOCALE_DIR); try { Portable.AddLocalFontFile(FileResourcePath.GetDataPath("bless-courier.ttf")); } catch (Exception) { System.Console.WriteLine("Warning: Could not add built-in Courier font, will fall back to system Courier font as needed."); } // load main window from GtkBuilder XML Gtk.Builder builder = new Gtk.Builder(); builder.AddFromFile(FileResourcePath.GetDataPath("ui", "MainWindow.ui")); builder.Autoconnect(this); // set the application icon MainWindow.Icon = new Gdk.Pixbuf(FileResourcePath.GetDataPath("bless-48x48.png")); string blessConfDir = FileResourcePath.GetUserPath(); // make sure local configuration directory exists try { if (!Directory.Exists(blessConfDir)) { Directory.CreateDirectory(blessConfDir); } } catch (Exception ex){ ErrorAlert ea = new ErrorAlert(Catalog.GetString("Cannot create user configuration directory"), ex.Message + Catalog.GetString("\n\nSome features of Bless may not work properly."), MainWindow); ea.Run(); ea.Destroy(); } Preferences.Proxy.Enable = false; // load default preferences Preferences.Default.Load(FileResourcePath.GetDataPath("default-preferences.xml")); Preferences.Default["Default.Layout.File"] = FileResourcePath.GetDataPath("bless-default.layout"); // load user preferences LoadPreferences(Path.Combine(blessConfDir, "preferences.xml")); Preferences.Instance.AutoSavePath = Path.Combine(blessConfDir, "preferences.xml"); // add the (empty) Menubar and toolbar uiManager = new UIManager(); MainWindow.AddAccelGroup(uiManager.AccelGroup); uiManager.AddUiFromString(uiXml); actionEntries = new ActionEntry[] { new ActionEntry ("File", null, Catalog.GetString("_File"), null, null, null), new ActionEntry ("Edit", null, Catalog.GetString("_Edit"), null, null, null), new ActionEntry ("View", null, Catalog.GetString("_View"), null, null, null), new ActionEntry ("Search", null, Catalog.GetString("_Search"), null, null, null), new ActionEntry ("Tools", null, Catalog.GetString("_Tools"), null, null, null), new ActionEntry ("Help", null, Catalog.GetString("_Help"), null, null, null) }; ActionGroup group = new ActionGroup ("MainMenuActions"); group.Add (actionEntries); group.Add ( new ToggleActionEntry[] { new ToggleActionEntry ("ToolbarAction", null, Catalog.GetString("Toolbar"), null, null, new EventHandler(OnViewToolbarToggled), false) }); uiManager.InsertActionGroup(group, 0); Widget mb = uiManager.GetWidget("/menubar"); MainVBox.PackStart(mb, false, false, 0); MainVBox.ReorderChild(mb, 0); Widget tb = uiManager.GetWidget("/toolbar"); tb.Visible = false; MainVBox.PackStart(tb, false, false, 0); MainVBox.ReorderChild(tb, 1); // create the DataBook dataBook = new DataBook(); dataBook.PageAdded += new DataView.DataViewEventHandler(OnDataViewAdded); dataBook.Removed += new RemovedHandler(OnDataViewRemoved); dataBook.SwitchPage += new SwitchPageHandler(OnSwitchPage); DataViewBox.PackStart(dataBook); // create the widget groups that hold utility widgets WidgetGroup widgetGroup0 = new WidgetGroup(); WidgetGroup widgetGroup1 = new WidgetGroup(); WidgetGroup sideWidgetGroup0 = new WidgetGroup(); WidgetGroup sideWidgetGroup1 = new WidgetGroup(); widgetGroup0.Show(); widgetGroup1.Show(); sideWidgetGroup0.Show(); sideWidgetGroup1.Show(); MainVBox.PackStart(widgetGroup0, false, false, 0); MainVBox.ReorderChild(widgetGroup0, 3); MainVBox.PackStart(widgetGroup1, false, false, 0); MainVBox.ReorderChild(widgetGroup1, 4); DataViewBox.PackStart(sideWidgetGroup0, false, false, 0); DataViewBox.ReorderChild(sideWidgetGroup0, 0); DataViewBox.PackEnd(sideWidgetGroup1, false, false, 0); //MainVBox.ReorderChild(widgetGroup1, 4); Services.File = new FileService(dataBook, MainWindow); Services.Session = new SessionService(dataBook, MainWindow); Services.UI = new UIService(uiManager); //Services.Info=new InfoService(infobar); // Add area plugins PluginManager.AddForType(typeof(AreaPlugin), new object[0]); PluginManager areaPlugins = PluginManager.GetForType(typeof(AreaPlugin)); foreach (AreaPlugin p in areaPlugins.Plugins) { Area.AddFactoryItem(p.Name, p.CreateArea); } // Load GUI plugins PluginManager.AddForType(typeof(GuiPlugin), new object[]{MainWindow, uiManager}); PluginManager guiPlugins = PluginManager.GetForType(typeof(GuiPlugin)); foreach (Plugin p in guiPlugins.Plugins) { guiPlugins.LoadPlugin(p); } // load recent file history try { History.Instance.Load(Path.Combine(blessConfDir, "history.xml")); } catch (Exception e) { System.Console.WriteLine(e.Message); } // if user specified files on the command line // try to load them if (args.Length > 0) { Services.File.LoadFiles(args); } else if (Preferences.Instance["Session.LoadPrevious"] == "True") { bool loadIt = true; string prevSessionFile = Path.Combine(blessConfDir, "last.session"); if (Preferences.Instance["Session.AskBeforeLoading"] == "True" && File.Exists(prevSessionFile)) { MessageDialog md = new MessageDialog (MainWindow, DialogFlags.DestroyWithParent, MessageType.Question, ButtonsType.YesNo, Catalog.GetString("Do you want to load your previous session?")); ResponseType result = (ResponseType)md.Run (); md.Destroy(); if (result == ResponseType.Yes) loadIt = true; else loadIt = false; } // try to load previous session if (loadIt) Services.Session.Load(prevSessionFile); } // if nothing has been loaded, create a new file if (dataBook.NPages == 0) { ByteBuffer bb = Services.File.NewFile(); // create and setup a DataView DataView dv = Services.File.CreateDataView(bb); // append the DataView to the DataBook dataBook.AppendView(dv, new CloseViewDelegate(Services.File.CloseFile), Path.GetFileName(bb.Filename)); } PreferencesChangedHandler handler = new PreferencesChangedHandler(OnPreferencesChanged); Preferences.Proxy.Subscribe("View.Toolbar.Show", "mainwin", handler); // register drag and drop of files MainWindow.DragDataReceived += OnDragDataReceived; Gtk.Drag.DestSet(MainWindow, DestDefaults.Motion | DestDefaults.Drop, dropTargets, Gdk.DragAction.Copy | Gdk.DragAction.Move); DataViewBox.ShowAll(); Preferences.Proxy.Enable = true; // fire the preferences changed event // so things are setup according to the preferences Preferences.Proxy.NotifyAll(); Application.Run(); } /// /// Handles drag and drop of files /// void OnDragDataReceived(object o, DragDataReceivedArgs args) { string uriStr = System.Text.Encoding.Default.GetString(args.SelectionData.Data); // get individual uris... // according to text/uri-list, uris are separated // by "\r\n" uriStr = uriStr.Trim(); uriStr = uriStr.Replace("\r\n", "\n"); string[] uris = uriStr.Split('\n'); // we are done Gtk.Drag.Finish (args.Context, false, false, args.Time); // load the files Services.File.LoadFiles(uris); } /// /// Updates the window's title with data from the specified DataView, /// if the specified DataView is active /// void UpdateWindowTitle(DataView dv) { if (dataBook.NPages == 0) return; DataView curdv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; ByteBuffer curbb = curdv.Buffer; ByteBuffer bb = dv.Buffer; // if DataView is active if (curbb == bb) { if (bb.HasChanged && !MainWindow.Title.EndsWith("* - Bless")) MainWindow.Title = bb.Filename + " * - Bless"; else if (!bb.HasChanged) MainWindow.Title = bb.Filename + " - Bless"; } } /// /// Load the preferences from the specified file /// void LoadPreferences(string path) { try { Preferences.Instance.Load(Preferences.Default); Preferences.Instance.Load(path); } catch (Exception e) { System.Console.WriteLine(e.Message); } } void OnPreferencesChanged(Preferences prefs) { ToggleAction viewToolbarAction = (ToggleAction)uiManager.GetAction("/menubar/View/Toolbar"); if (prefs["View.Toolbar.Show"] == "True") viewToolbarAction.Active = true; else viewToolbarAction.Active = false; } /// /// Callback for SwitchPage DataBook event /// void OnSwitchPage(object o, SwitchPageArgs args) { DataView dv = ((DataViewDisplay)dataBook.GetNthPage((int)args.PageNum)).View; UpdateWindowTitle(dv); dv.Display.GrabKeyboardFocus(); } void OnDataViewAdded(DataView dv) { dv.Buffer.Changed += new ByteBuffer.ChangedHandler(OnBufferContentsChanged); dv.BufferChanged += new DataView.DataViewEventHandler(OnBufferChanged); } void OnDataViewRemoved(object o, RemovedArgs args) { DataView dv = ((DataViewDisplay)args.Widget).View; dv.Buffer.Changed -= new ByteBuffer.ChangedHandler(OnBufferContentsChanged); dv.BufferChanged -= new DataView.DataViewEventHandler(OnBufferChanged); } void OnBufferChanged(DataView dv) { UpdateWindowTitle(dv); } ///Handle ByteBuffer changes void OnBufferContentsChanged(ByteBuffer bb) { Gtk.Application.Invoke(delegate { DataView dv = null; // find DataView that owns bb foreach (DataViewDisplay dvtemp in dataBook.Children) { if (dvtemp.View.Buffer == bb) { dv = dvtemp.View; break; } } UpdateWindowTitle(dv); }); } ///Handle the View->Toolbar command public void OnViewToolbarToggled(object o, EventArgs args) { ToggleAction viewToolbarAction = (ToggleAction)uiManager.GetAction("/menubar/View/Toolbar"); Preferences.Proxy.Change("View.Toolbar.Show", viewToolbarAction.Active.ToString(), "mainwin"); Widget mainToolbar = uiManager.GetWidget("/toolbar"); if (viewToolbarAction.Active) mainToolbar.Visible = true; else mainToolbar.Visible = false; } ///Handle the Benchmark Toolbar button command (Hidden) public void OnBenchmark(object o, EventArgs args) { if (dataBook.NPages > 0) { DataViewDisplay dvd = (DataViewDisplay)dataBook.CurrentPageWidget; dvd.Benchmark(); } } ///Handle Main Window Delete Event public void OnMainWindowDeleteEvent (object o, DeleteEventArgs args) { // make sure we can quit safely: // 1. no file operations are currently going on (eg save, replace etc) // 2. user has saved or doesn't want to save their modified files MenuItem FileQuitMenuItem = (MenuItem)uiManager.GetWidget("/menubar/File/Quit"); if (FileQuitMenuItem.Sensitive) Services.File.TryQuit(); args.RetVal = true; } } // end bless main bless-0.6.3/src/gui/Services.cs000066400000000000000000000024551374060072200163240ustar00rootroot00000000000000// created on 4/30/2006 at 11:49 AM /* * Copyright (c) 2006, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ namespace Bless.Gui { public class Services { static FileService fileService; static SessionService sessionService; static UIService uiService; public static FileService File { get { return fileService; } set { fileService = value; } } public static SessionService Session { get { return sessionService; } set { sessionService = value; } } public static UIService UI { get { return uiService; } set { uiService = value; } } } }bless-0.6.3/src/gui/SessionService.cs000066400000000000000000000072261374060072200175060ustar00rootroot00000000000000// created on 4/30/2006 at 11:57 AM /* * Copyright (c) 2006, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using Gtk; using Bless.Tools; using Bless.Buffers; using Bless.Gui.Dialogs; using System.IO; namespace Bless.Gui { public class SessionService { DataBook dataBook; Window mainWindow; public SessionService(DataBook db, Window mw) { dataBook = db; mainWindow = mw; } /// /// Save the current session to the specified file. /// public void Save(string path) { Session session = new Session(); Gdk.Rectangle alloc = mainWindow.Allocation; // save the window size session.WindowHeight = alloc.Height; session.WindowWidth = alloc.Width; // save information about the currently open files foreach(DataViewDisplay dvd in dataBook.Children) { DataView dv = dvd.View; // add to session only if buffer is related to a file if (dv.Buffer.HasFile) { session.AddFile(dv.Buffer.Filename, dv.Offset, dv.CursorOffset, dv.CursorDigit, dvd.Layout.FilePath, 0); if (dv == ((DataViewDisplay)dataBook.CurrentPageWidget).View) { session.ActiveFile = dv.Buffer.Filename; } } } session.Save(path); } /// /// Load a session from the specified file. /// public void Load(string path) { Session session = new Session(); // try to load session file try { session.Load(path); } catch (Exception ex) { System.Console.WriteLine(ex.Message); return; } // set the size of main window if (Preferences.Instance["Session.RememberWindowGeometry"] == "True") mainWindow.Resize(session.WindowWidth, session.WindowHeight); // add files to the DataBook foreach(SessionFileInfo sfi in session.Files) { ByteBuffer bb = Services.File.OpenFile(sfi.Path); // if file was opened successfully if (bb != null) { DataView dv = Services.File.CreateDataView(bb); // try to load layout file try { dv.Display.Layout = new Bless.Gui.Layout(sfi.Layout); } catch (Exception ex) { ErrorAlert ea = new ErrorAlert("Error loading layout '" + sfi.Layout + "' for file '" + sfi.Path + "'. Loading default layout.", ex.Message , mainWindow); ea.Run(); ea.Destroy(); } long cursorOffset = sfi.CursorOffset; // sanity check cursor offset and view offset if (cursorOffset > bb.Size) cursorOffset = bb.Size; long offset = sfi.Offset; if (offset >= bb.Size) offset = 0; if (Preferences.Instance["Session.RememberCursorPosition"] == "True") { dv.MoveCursor(cursorOffset, sfi.CursorDigit); dv.Offset = offset; } dataBook.AppendView(dv, new CloseViewDelegate(Services.File.CloseFile), Path.GetFileName(bb.Filename)); //OnBufferChanged(bb); } } foreach(DataViewDisplay dvd in dataBook.Children) { DataView dv = dvd.View; if (dv.Buffer.Filename == session.ActiveFile) { dataBook.CurrentPage = dataBook.PageNum(dvd); break; } } } } }bless-0.6.3/src/gui/UIService.cs000066400000000000000000000034401374060072200163720ustar00rootroot00000000000000// created on 4/1/2007 at 2:12 PM /* * Copyright (c) 2007, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using Gtk; using Bless.Util; namespace Bless.Gui { public interface IInfoDisplay { void DisplayMessage(string message); void ClearMessage(); } public interface IProgressDisplay { ProgressCallback NewCallback(); } /// /// Provides services related to the UI /// public class UIService { UIManager uiManager; IInfoDisplay infoDisplay; IProgressDisplay progressDisplay; public UIService(UIManager uim) { uiManager = uim; } /// /// Service for showing status messages /// public IInfoDisplay Info { get { return infoDisplay; } set { infoDisplay = value; } } /// /// Service for displaying the progress of various actions /// public IProgressDisplay Progress { get { return progressDisplay; } set { progressDisplay = value; } } /// /// The global UIManager /// public UIManager Manager { get { return uiManager;} } } } // end namespacebless-0.6.3/src/gui/WidgetGroup.cs000066400000000000000000000026221374060072200167750ustar00rootroot00000000000000/* * Copyright (c) 2006, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using Gtk; namespace Bless.Gui { public class WidgetGroup : HBox { public WidgetGroup() { } protected override void OnAdded(Widget w) { w.Hide(); w.Shown += OnWidgetShown; base.OnAdded(w); } protected override void OnRemoved(Widget w) { w.Shown -= OnWidgetShown; base.OnRemoved(w); } void OnWidgetShown(object sender, EventArgs e) { Widget w = (Widget)sender; // Make sure only one widget is visible foreach(Widget child in Children) { if (child != w) child.Hide(); } // don't use ShowAll(): causes loop this.Show(); } } } bless-0.6.3/src/gui/areas/000077500000000000000000000000001374060072200152775ustar00rootroot00000000000000bless-0.6.3/src/gui/areas/Area.cs000066400000000000000000000471131374060072200165040ustar00rootroot00000000000000// created on 6/14/2004 at 10:39 PM /* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using Bless.Gui.Drawers; using Bless.Util; using Bless.Buffers; using Bless.Tools.Find; using System.Collections.Generic; using System.Xml; namespace Bless.Gui.Areas { /// /// An area on the screen that displays data in a specific way. /// public abstract class Area { protected AreaGroup areaGroup; protected Drawer drawer; protected Drawer.Information drawerInformation; protected string type; // display protected int x; protected int y; protected int width; protected int height; protected int bpr; protected int dpb; // digits per byte protected int fixedBpr; protected Gdk.Drawable backPixmap; protected bool manualDoubleBuffer; protected bool isAreaRealized; // GC's protected Gdk.GC cursorGC; protected Gdk.GC activeCursorGC; protected Gdk.GC inactiveCursorGC; protected int cursorDigit; protected bool cursorFocus; protected bool canFocus; public enum RenderMergeFlags {None = 0, Left = 1, Right = 2} // Abstract methods /// /// Render (a part of) a row normally (without highlighting) /// /// /// The row to render. /// /// /// The offset of the byte in the row to start rendering. /// /// /// The number of bytes to render. /// /// /// Whether to blank the background before rendering. /// abstract protected void RenderRowNormal(int i, int p, int n, bool blank); /// /// Render (a part of) a row with highlighting. /// /// /// The row to render. /// /// /// The offset of the byte in the row to start rendering. /// /// /// The number of bytes to render. /// /// /// Whether to blank the background before rendering. /// abstract protected void RenderRowHighlight(int i, int p, int n, bool blank, Drawer.HighlightType ht); /// /// Get info about where a specified buffer offset is currently displayed. /// /// /// The offset to query. /// /// /// The row the offset is displayed in. /// /// /// The byte in the row the offset is displayed on. /// /// /// The X coordinate of the displayed position. /// /// /// The Y coordinate of the displayed position. /// abstract public void GetDisplayInfoByOffset(long off, out int orow, out int obyte, out int ox, out int oy); /// /// Flags containing extra info about positions in the view. /// public enum GetOffsetFlags { /// Position is beyond the end of file Eof = 1, /// Position is between bytes (in the so-called abyss) Abyss = 2 } /// /// Gets the offset in the buffer that is displayed at specified location in the area /// /// /// The X coordinate of the queried location. /// /// /// The Y coordinate of the queried location. /// /// /// The digit of the byte at the specified location. /// /// /// Some flags with additional info about the location (). /// /// /// The offset of the byte at the specified location. /// abstract public long GetOffsetByDisplayInfo(int x, int y, out int digit, out GetOffsetFlags rflags); /// /// Special key handler for the area. /// /// /// The key that was pressed. /// /// /// Whether we are in overwrite mode. /// /// /// Whether the key was actually handled. /// virtual public bool HandleKey(Gdk.Key key, bool overwrite) { return false; } /// /// Calculates the width in pixels the /// area will occupy with n bytes per row. /// abstract public int CalcWidth(int n, bool force); /// /// A delegate that creates instances of area types. /// public delegate Area AreaCreatorFunc(AreaGroup ag); /// /// A dictionary to hold area type names and creation functions /// static private Dictionary pluginTable; /// /// Adds a new area type to the factory. /// /// /// The name of the area type /// /// /// The delegate to call to create an instance of this area type. /// /// This is used by plugins to register new area types. static public void AddFactoryItem(string name, AreaCreatorFunc createArea) { if (pluginTable == null) { pluginTable = new Dictionary(); } // System.Console.WriteLine("Adding plugin name {0}", name); pluginTable.Add(name, createArea); } /// /// Factory method to create instances of area types by name. /// /// /// The name of the type of the area to create. /// /// /// The this area will belong in. /// /// /// The created area. /// static public Area Factory(string name, AreaGroup ag) { try { AreaCreatorFunc acf = pluginTable[name]; return acf(ag); } catch (KeyNotFoundException e) { System.Console.WriteLine(e.Message); } return null; } /// /// Create an area. /// /// /// The this area will belong in. /// public Area(AreaGroup areaGroup) { this.areaGroup = areaGroup; drawerInformation = new Drawer.Information(); canFocus = false; dpb = 0; fixedBpr = -1; isAreaRealized = false; } /// /// Configure an area using an xml configuration. /// /// /// The that holds the configuration for this area. /// /// This is overriden by inherited classes to accept extra options public virtual void Configure(XmlNode parentNode) { XmlNodeList childNodes = parentNode.ChildNodes; foreach(XmlNode node in childNodes) { if (node.Name == "bpr") this.FixedBytesPerRow = System.Convert.ToInt32(node.InnerText); if (node.Name == "display") ParseDisplay(node, drawerInformation); } } ///Parse the tag in layout files void ParseDisplay(XmlNode parentNode, Drawer.Information info) { XmlNodeList childNodes = parentNode.ChildNodes; foreach(XmlNode node in childNodes) { if (node.Name == "evenrow") ParseDisplayRow(node, info, Drawer.RowType.Even); else if (node.Name == "oddrow") ParseDisplayRow(node, info, Drawer.RowType.Odd); else if (node.Name == "font") info.FontName = node.InnerText; } } void ParseDisplayRow(XmlNode parentNode, Drawer.Information info, Drawer.RowType rowType) { Drawer.Color fg, bg; XmlNodeList childNodes = parentNode.ChildNodes; foreach(XmlNode node in childNodes) { ParseDisplayType(node, out fg, out bg); if (node.Name == "evencolumn") { if (bg != null) info.bgNormal[(int)rowType, (int)Drawer.ColumnType.Even] = bg; if (fg != null) info.fgNormal[(int)rowType, (int)Drawer.ColumnType.Even] = fg; } else if (node.Name == "oddcolumn") { if (bg != null) info.bgNormal[(int)rowType, (int)Drawer.ColumnType.Odd] = bg; if (fg != null) info.fgNormal[(int)rowType, (int)Drawer.ColumnType.Odd] = fg; } else if (node.Name == "selectedcolumn") { if (bg != null) info.bgHighlight[(int)rowType, (int)Drawer.HighlightType.Selection] = bg; if (fg != null) info.fgHighlight[(int)rowType, (int)Drawer.HighlightType.Selection] = fg; } else if (node.Name == "patternmatchcolumn") { if (bg != null) info.bgHighlight[(int)rowType, (int)Drawer.HighlightType.PatternMatch] = bg; if (fg != null) info.fgHighlight[(int)rowType, (int)Drawer.HighlightType.PatternMatch] = fg; } } } ///Parse a font type void ParseDisplayType(XmlNode parentNode, out Drawer.Color fg, out Drawer.Color bg) { fg = null; bg = null; XmlNodeList childNodes = parentNode.ChildNodes; foreach(XmlNode node in childNodes) { Gdk.Color col = new Gdk.Color(); if (node.Name == "foreground") { Gdk.Color.Parse(node.InnerText, ref col); Gdk.Colormap.System.AllocColor(ref col, false, true); fg = new Drawer.Color(col); } if (node.Name == "background") { Gdk.Color.Parse(node.InnerText, ref col); Gdk.Colormap.System.AllocColor(ref col, false, true); bg = new Drawer.Color(col); } } } /// /// Realize the area. /// public virtual void Realize() { Gtk.DrawingArea da = areaGroup.DrawingArea; backPixmap = da.GdkWindow; activeCursorGC = new Gdk.GC(da.GdkWindow); inactiveCursorGC = new Gdk.GC(da.GdkWindow); Gdk.Color col = new Gdk.Color(); Gdk.Color.Parse("red", ref col); activeCursorGC.RgbFgColor = col; Gdk.Color.Parse("gray", ref col); inactiveCursorGC.RgbFgColor = col; cursorGC = activeCursorGC; isAreaRealized = true; } // Properties // public int X { set { x = value; } get { return x; } } public int Y { set { y = value; } get { return y; } } public int Width { set { width = value; } get { return width; } } public int Height { set { height = value; } get { return height; } } public int BytesPerRow { set { bpr = value; } get { return bpr; } } public int FixedBytesPerRow { set { fixedBpr = value; } get { return fixedBpr; } } public int DigitsPerByte { get { return dpb; } } public int CursorDigit { get { return cursorDigit; } set { if (value >= dpb) cursorDigit = dpb - 1; else cursorDigit = value; } } public bool HasCursorFocus { set { cursorFocus = value; } get { return cursorFocus;} } public bool CanFocus { get { return canFocus;} } public Drawer.Information DrawerInformation { get { return drawerInformation; } set { drawerInformation = value; } } public virtual Drawer Drawer { get { return drawer; } } public string Type { get { return type; } } public bool IsActive { set { if (value == true) cursorGC = activeCursorGC; else cursorGC = inactiveCursorGC; // doesn't actually change cursor position // just redraws it with correct color //MoveCursor(cursorOffset, cursorDigit); } get { return cursorGC == activeCursorGC; } } /// /// This method is only called to draw extra stuff when doing a complete /// redraw of the area /// internal protected virtual void RenderExtra() { } void RenderRangeHelper(Drawer.HighlightType ht, int rstart, int bstart, int len) { if (ht != Drawer.HighlightType.Normal) RenderRowHighlight(rstart, bstart, len, false, ht); else RenderRowNormal(rstart, bstart, len, false); } /// /// Render the bytes in the highlight range. /// /// /// A /// /// /// Whether to visually merge the highlight with adjacent ones left and/or right. /// /// /// This method doesn't check whether the merge flags are correct (eg there is indeed /// a similar adjacent highlight). It just draws the highlight in such a way as /// to appear merged to any similar highlights if they exist. /// internal protected virtual void RenderHighlight(Highlight h, Drawer.HighlightType left, Drawer.HighlightType right) { if (isAreaRealized == false) return; int rstart, bstart, xstart, ystart; int rend, bend, xend, yend; bool odd; Gdk.GC gc; Gdk.GC oddGC; Gdk.GC evenGC; Gdk.GC leftGC; Gdk.GC rightGC; oddGC = drawer.GetBackgroundGC(Drawer.RowType.Odd, h.Type); evenGC = drawer.GetBackgroundGC(Drawer.RowType.Even, h.Type); GetDisplayInfoByOffset(h.Start, out rstart, out bstart, out xstart, out ystart); GetDisplayInfoByOffset(h.End, out rend, out bend, out xend, out yend); //System.Console.WriteLine("Start {0:x} {1} {2} x:{3} y:{4}", h.Start, rstart, bstart, xstart, ystart); //System.Console.WriteLine("End {0:x} {1} {2} x:{3} y:{4}", h.End, rend, bend, xend, yend); bool drawLeft = false; int dxstart = xstart; if (bstart > 0) { int digit; GetOffsetFlags gof; GetOffsetByDisplayInfo(xstart - 1, ystart, out digit, out gof); if ((gof & GetOffsetFlags.Abyss) != 0) { dxstart -= drawer.Width; drawLeft = true; } } bool drawRight = false; int dxend = xend; if (bend < bpr - 1) { int digit; GetOffsetFlags gof; GetOffsetByDisplayInfo(xend + dpb*drawer.Width, yend, out digit, out gof); if ((gof & GetOffsetFlags.Abyss) != 0) { dxend += drawer.Width; drawRight = true; } } // if the whole range is on one row if (rstart == rend) { if (areaGroup.ManualDoubleBuffer) { BeginPaint(x + dxstart, y + ystart, dxend - dxstart + dpb*drawer.Width, drawer.Height); } // odd row? odd = (((h.Start / bpr) % 2) == 1); if (odd) { gc = oddGC; leftGC = drawer.GetBackgroundGC(Drawer.RowType.Odd, left); rightGC = drawer.GetBackgroundGC(Drawer.RowType.Odd, right); } else { gc = evenGC; leftGC = drawer.GetBackgroundGC(Drawer.RowType.Even, left); rightGC = drawer.GetBackgroundGC(Drawer.RowType.Even, right); } //render if (drawLeft) backPixmap.DrawRectangle(leftGC, true, x + dxstart, y + ystart, drawer.Width, drawer.Height); if (drawRight) backPixmap.DrawRectangle(rightGC, true, x + xend + dpb*drawer.Width, y + yend, drawer.Width, drawer.Height); backPixmap.DrawRectangle(gc, true, x + xstart, y + ystart, xend - xstart + dpb*drawer.Width, drawer.Height); RenderRangeHelper(h.Type, rstart, bstart, bend - bstart + 1); } else { // multi-row range if (areaGroup.ManualDoubleBuffer) { // handle double-buffering Gdk.Region paintRegion = new Gdk.Region(); Gdk.Rectangle rectStart = new Gdk.Rectangle(x + dxstart, y + ystart, width - dxstart, drawer.Height); Gdk.Rectangle rectMiddle; if (rend > rstart + 1) rectMiddle = new Gdk.Rectangle(x, y + ystart + drawer.Height, width, yend - ystart - drawer.Height); else rectMiddle = Gdk.Rectangle.Zero; Gdk.Rectangle rectEnd = new Gdk.Rectangle(x, y + yend, dxend + dpb*drawer.Width, drawer.Height); paintRegion.UnionWithRect(rectStart); paintRegion.UnionWithRect(rectMiddle); paintRegion.UnionWithRect(rectEnd); BeginPaintRegion(paintRegion); } // render first row odd = (((h.Start / bpr) % 2) == 1); if (odd) { gc = oddGC; leftGC = drawer.GetBackgroundGC(Drawer.RowType.Odd, left); rightGC = drawer.GetBackgroundGC(Drawer.RowType.Odd, right); } else { gc = evenGC; leftGC = drawer.GetBackgroundGC(Drawer.RowType.Even, left); rightGC = drawer.GetBackgroundGC(Drawer.RowType.Even, right); } if (drawLeft) backPixmap.DrawRectangle(leftGC, true, x + dxstart, y + ystart, drawer.Width, drawer.Height); backPixmap.DrawRectangle(gc, true, x + xstart, y + ystart, width - xstart, drawer.Height); RenderRangeHelper(h.Type, rstart, bstart, bpr - bstart); long curOffset = h.Start + bpr - bstart; // render middle rows for (int i = rstart + 1;i < rend;i++) { odd = (((curOffset / bpr) % 2) == 1); if (odd) gc = oddGC; else gc = evenGC; backPixmap.DrawRectangle(gc, true, x, y + i*drawer.Height, width, drawer.Height); RenderRangeHelper(h.Type, i, 0, bpr); curOffset += bpr; } // render last row odd = (((h.End / bpr) % 2) == 1); if (odd) { gc = oddGC; leftGC = drawer.GetBackgroundGC(Drawer.RowType.Odd, left); rightGC = drawer.GetBackgroundGC(Drawer.RowType.Odd, right); } else { gc = evenGC; leftGC = drawer.GetBackgroundGC(Drawer.RowType.Even, left); rightGC = drawer.GetBackgroundGC(Drawer.RowType.Even, right); } if (drawRight) backPixmap.DrawRectangle(rightGC, true, x + xend + dpb*drawer.Width, y + yend, drawer.Width, drawer.Height); backPixmap.DrawRectangle(gc, true, x, y + yend, xend + dpb*drawer.Width, drawer.Height); RenderRangeHelper(h.Type, rend, 0, bend + 1); } if (areaGroup.ManualDoubleBuffer) { EndPaint(); } } /// /// Blanks the selected offset /// /// /// A /// internal protected void BlankOffset(long offs) { if (isAreaRealized == false) return; int nrows = height / drawer.Height; long bytesInView = nrows * bpr; if (offs >= areaGroup.Offset && offs < areaGroup.Offset + bytesInView) { int pcRow, pcByte, pcX, pcY; GetDisplayInfoByOffset(offs, out pcRow, out pcByte, out pcX, out pcY); Gdk.GC backEvenGC = drawer.GetBackgroundGC(Drawer.RowType.Even, Drawer.HighlightType.Normal); backPixmap.DrawRectangle(backEvenGC, true, x + pcX, y + pcY, drawer.Width*dpb, drawer.Height); } } ///Render the cursor internal protected void RenderCursor() { if (isAreaRealized == false) return; int cRow, cByte, cX, cY; GetDisplayInfoByOffset(areaGroup.CursorOffset, out cRow, out cByte, out cX, out cY); backPixmap.DrawRectangle(cursorGC, true, x + cX, y + cY + drawer.Height - 2, drawer.Width*dpb, 2); if (cursorFocus) { backPixmap.DrawRectangle(cursorGC, true, x + cX + cursorDigit*drawer.Width, y + cY, 1, drawer.Height - 2); } } /// /// Dispose the (server side) pixmaps used by this area. /// public void DisposePixmaps() { if (isAreaRealized == false) return; backPixmap.Dispose(); drawer.DisposePixmaps(); } void BeginPaintRegion(Gdk.Region r) { Gdk.Window win = areaGroup.DrawingArea.GdkWindow; win.BeginPaintRegion(r); } void BeginPaint() { BeginPaint(this.x, this.y, this.width, this.height); } void BeginPaint(int x, int y, int w, int h) { Gdk.Window win = areaGroup.DrawingArea.GdkWindow; win.BeginPaintRect(new Gdk.Rectangle(x, y, w, h)); } void EndPaint() { areaGroup.DrawingArea.GdkWindow.EndPaint(); } internal virtual void BlankBackground() { Gdk.GC backEvenGC = drawer.GetBackgroundGC(Drawer.RowType.Even, Drawer.HighlightType.Normal); backPixmap.DrawRectangle(backEvenGC, true, x, y, width, height); } internal virtual void BlankEof() { int pcRow, pcByte, pcX, pcY; GetDisplayInfoByOffset(areaGroup.Buffer.Size, out pcRow, out pcByte, out pcX, out pcY); Gdk.GC backEvenGC = drawer.GetBackgroundGC(Drawer.RowType.Even, Drawer.HighlightType.Normal); backPixmap.DrawRectangle(backEvenGC, true, x + pcX, y + pcY, drawer.Width*dpb, drawer.Height); } public virtual void ShowPopup(Gtk.UIManager uim) { Gtk.Widget popup = uim.GetWidget("/DefaultAreaPopup"); (popup as Gtk.Menu).Popup(); } }// Area } //namespace bless-0.6.3/src/gui/areas/AreaGroup.cs000066400000000000000000000433651374060072200175260ustar00rootroot00000000000000// Created on 12:43 AM 19/3/2008 /* * Copyright (c) 2008, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.Collections.Generic; using Bless.Buffers; using Bless.Util; using Bless.Gui.Drawers; namespace Bless.Gui.Areas { /// /// An atomic highlight /// class AtomicHighlight : Highlight { IList containers; public IList Containers { get { return containers; } } /// /// Adds a highlight as a container of this atomic highlight /// /// The highlight is added only if it has lower or equal priority than this highlight public void AddContainer(Highlight h) { if (h.Type > type) return; // insertion sort (higher priority first) for (int i = 0; i < containers.Count; i++) { if (h.Type >= containers[i].Type) { containers.Insert(i, h); return; } } containers.Add(h); } /// /// /// public void GetAbyssHighlights(out Drawer.HighlightType left, out Drawer.HighlightType right) { left = Drawer.HighlightType.Sentinel; right = Drawer.HighlightType.Sentinel; foreach(Highlight h in containers) { if (left == Drawer.HighlightType.Sentinel && h.Contains(start - 1)) left = h.Type; if (right == Drawer.HighlightType.Sentinel && h.Contains(end + 1)) right = h.Type; } if (left == Drawer.HighlightType.Sentinel) left = Drawer.HighlightType.Normal; if (right == Drawer.HighlightType.Sentinel) right = Drawer.HighlightType.Normal; } public AtomicHighlight(Highlight parent) : base(parent) { this.containers = new System.Collections.Generic.List(1); this.containers.Add(parent); } public AtomicHighlight(AtomicHighlight h) : base(h) { this.containers = new System.Collections.Generic.List(h.containers); } public override string ToString() { string str = base.ToString() + " Containers: "; foreach(Highlight h in containers) { str += h.ToString() + ", "; } Drawer.HighlightType left, right; this.GetAbyssHighlights(out left, out right); str += string.Format("Left: {0} Right: {0}", left, right); return str; } } /// /// A group of areas that display data from the same source /// and are synchronized. /// public class AreaGroup { IList areas; ByteBuffer byteBuffer; Gtk.DrawingArea drawingArea; Area focusedArea; IntervalTree highlights; enum Changes { Offset = 1, Cursor = 2, Highlights = 4} Changes changes; bool manualDoubleBuffer; // current offset of view in the buffer long offset; // current cursor long cursorOffset; // track changes long prevCursorOffset; byte[] bufferCache; /// /// The previous atomic highlight ranges of the view. /// These are non-overlapping ranges that describe the highlighting of the whole view /// and can be used to render it quickly. They are also used to minimize /// redrawing when possible () /// IntervalTree prevAtomicHighlights; Highlight selection; public IList Areas { get { return areas; } } public Area FocusedArea { get { return focusedArea; } set { UpdateFocusedArea(value); } } public long Offset { get { return offset;} set { if (offset == value) return; offset = value; SetChanged(Changes.Offset); } } public long CursorOffset { get { return cursorOffset;} } public int CursorDigit { get { if (focusedArea != null) return focusedArea.CursorDigit; else return 0; } } public long PrevCursorOffset { get { return prevCursorOffset;} } public ByteBuffer Buffer { get { return byteBuffer; } set { byteBuffer = value; SetChanged(Changes.Offset);} } public Gtk.DrawingArea DrawingArea { get { return drawingArea; } set { drawingArea = value; } } public Util.Range Selection { get { return selection; } set { if (selection == value) return; highlights.Delete(selection); selection.Start = value.Start; selection.End = value.End; // make sure the cursor is also updated (because it may // not have changed position so SetCursor() won't render it // but it may have to become visible again eg when a selection is cleared) SetChanged(Changes.Highlights | Changes.Cursor); } } internal bool ManualDoubleBuffer { get { return manualDoubleBuffer; } } public void SetCursor(long coffset, int cdigit) { prevCursorOffset = cursorOffset; // if there is no change ignore... if (cursorOffset == coffset && this.CursorDigit == cdigit) return; cursorOffset = coffset; foreach(Area a in areas) a.CursorDigit = cdigit; SetChanged(Changes.Cursor); } public byte GetCachedByte(long pos) { return bufferCache[pos - offset]; } public AreaGroup() { areas = new System.Collections.Generic.List(); highlights = new IntervalTree(); selection = new Highlight(Drawer.HighlightType.Selection); prevAtomicHighlights = new IntervalTree(); bufferCache = new byte[0]; } /// /// Get the range of bytes and the number of rows that /// are displayed in the current view. /// public Util.Range GetViewRange(out int nrows) { // find out number of rows, bytes in current view int minRows = int.MaxValue; int minBpr = int.MaxValue; foreach (Area a in areas) { minRows = Math.Min(minRows, a.Height / a.Drawer.Height); minBpr = Math.Min(minBpr, a.BytesPerRow); } nrows = minRows; long bleft = minRows * minBpr; if (bleft + offset >= byteBuffer.Size) bleft = byteBuffer.Size - offset; // make sure we get an empty clipping Range when bleft==0 if (bleft > 0) return new Util.Range(offset, offset + bleft - 1); else return new Util.Range(); } /// /// Whether a has changed. /// private bool HasChanged(Changes c) { return ((changes & c) != 0); } /// /// Whether anything has changed. /// private bool HasAnythingChanged() { return changes != 0; } /// /// Clear all changes /// private void ClearChanges() { changes = 0; } /// /// Set a as changed. /// /// /// A /// ///This causes the group to be rendered again. private void SetChanged(Changes c) { changes |= c; Gtk.Application.Invoke(delegate { if (drawingArea == null || drawingArea.GdkWindow == null) return; if (HasChanged(Changes.Offset)) { Gdk.Rectangle view = drawingArea.Allocation; view.X = 0; view.Y = 0; drawingArea.GdkWindow.BeginPaintRect(view); Render(false); drawingArea.GdkWindow.EndPaint(); } else ExposeManually(); }); } /// /// Render this group, manually handling the double buffering /// private void ExposeManually() { manualDoubleBuffer = true; Render(false); manualDoubleBuffer = false; } /// /// Invalidate this group (visually). This forces a complete redraw /// on the next Render(). /// public void Invalidate() { changes |= Changes.Offset; } /// /// Invalidate this group (visually). This forces a complete redraw /// on the next Render(). /// public void RedrawNow() { SetChanged(Changes.Offset); } private void InitializeHighlights() { ClearHighlights(); if (!selection.IsEmpty()) highlights.Insert(selection); } /// /// Adds a highlight on a range of data. /// public void AddHighlight(long start, long end, Drawer.HighlightType ht) { highlights.Insert(new Highlight(start, end, ht)); changes |= Changes.Highlights; } private void ClearHighlights() { highlights.Clear(); } private void SetupBufferCache() { int nrows; Util.Range view = GetViewRange(out nrows); if (view.Size != bufferCache.Length) bufferCache = new byte[view.Size]; for(int i = 0; i < view.Size; i++) bufferCache[i] = byteBuffer[view.Start + i]; } public void CycleFocus() { int faIndex; for (faIndex = 0; faIndex < areas.Count; faIndex++) if (focusedArea == areas[faIndex]) break; if (faIndex >= areas.Count) faIndex = -1; int end = faIndex + areas.Count; // use < instead of != so this will work correctly // even when faIndex = -1 in which case we should check // all areas (instead of only the rest areas.Count - 1 // areas when there is already a focused area) for (faIndex++; faIndex < end; faIndex++) { Area a = (areas[faIndex%areas.Count] as Area); if (a.CanFocus == true) { UpdateFocusedArea(a); return; } } focusedArea = null; } private void UpdateFocusedArea(Area fa) { focusedArea = fa; foreach(Area a in areas) a.HasCursorFocus = false; focusedArea.HasCursorFocus = true; // set the previous cursor so that when // the screen is rendered the byte under the // cursor is properly cleared (before being drawn // again) prevCursorOffset = cursorOffset; SetChanged(Changes.Cursor); } /// /// Renders the extra (data independent) portions of the view /// private void RenderExtra() { foreach(Area a in areas) { a.RenderExtra(); } } /// /// Renders a of data using a specified /// private void RenderHighlight(AtomicHighlight h) { Drawer.HighlightType left; Drawer.HighlightType right; h.GetAbyssHighlights(out left, out right); //System.Console.WriteLine(" Rendering {0} ({1} {2})", h, left, right); foreach(Area a in areas) { a.RenderHighlight(h, left, right); } } /// /// Blanks the view background /// private void BlankBackground() { foreach(Area a in areas) { a.BlankBackground(); } } private AtomicHighlight[] SplitAtomicPrioritized(AtomicHighlight q, Highlight r) { AtomicHighlight[] ha; if (q.Type > r.Type) { ha = new AtomicHighlight[3]{new AtomicHighlight(r), new AtomicHighlight(q), new AtomicHighlight(r)}; Util.Range.SplitAtomic(ha, r, q); ha[1].AddContainer(r); } else { ha = new AtomicHighlight[3]{new AtomicHighlight(q), new AtomicHighlight(r), new AtomicHighlight(q)}; Util.Range.SplitAtomic(ha, q, r); foreach (Highlight h in q.Containers) ha[1].AddContainer(h); } return ha; } /// /// Breaks down a base highlight and produces atomic highlights /// private IntervalTree BreakDownHighlights(Highlight s, IList lst) { //System.Console.WriteLine("breaking down {0}", s); IntervalTree it = new IntervalTree(); if (!s.IsEmpty()) it.Insert(new AtomicHighlight(s)); foreach(Highlight r in lst) { //System.Console.WriteLine(" Processing {0}", r); IList overlaps = it.SearchOverlap(r); foreach(AtomicHighlight q in overlaps) { it.Delete(q); //System.Console.WriteLine(" Overlap {0}", q); AtomicHighlight[] ha = SplitAtomicPrioritized(q, r); foreach(AtomicHighlight h in ha) { // Keep only common parts to avoid duplications. // This also has the useful side effect that everything // is clipped inside s h.Intersect(q); //System.Console.WriteLine(" Atomic {0}", h); if (!h.IsEmpty()) { it.Insert(h); } } } } //foreach(AtomicHighlight ah in it.GetValues()) { // System.Console.WriteLine(" " + ah); //} return it; } /// /// Gets the atomic highlight ranges of the current view. /// (Non-overlapping ranges that describe the highlighting of the whole view) /// private IntervalTree GetAtomicHighlights() { int nrows; Util.Range clip = GetViewRange(out nrows); Highlight view = new Highlight(clip, Drawer.HighlightType.Normal); // get all highlights in current view IList viewableHighlights = highlights.SearchOverlap(view); return BreakDownHighlights(view, viewableHighlights); } /// /// Renders the area group based on the specified atomic highlights. /// private void RenderAtomicHighlights(IntervalTree atomicHighlights) { IList hl = atomicHighlights.GetValues(); foreach(AtomicHighlight h in hl) { RenderHighlight(h); } } /// /// Render the whole view. /// /// /// The current atomic highlight ranges /// private void RenderAll(IntervalTree atomicHighlights) { SetupBufferCache(); // blank the background BlankBackground(); RenderExtra(); RenderAtomicHighlights(atomicHighlights); RenderCursor(atomicHighlights); } /// /// Render the new highlights taking into consideration the old highlights /// (this means that only the differences are actually rendered) /// private void RenderHighlightDiffs(IntervalTree atomicHighlights) { //System.Console.WriteLine("Rendering highlight diffs"); IList hl = atomicHighlights.GetValues(); foreach(AtomicHighlight h in hl) { //System.Console.WriteLine(" Checking {0}", h); IList overlaps = prevAtomicHighlights.SearchOverlap(h); foreach(AtomicHighlight overlap in overlaps) { AtomicHighlight hTmp = new AtomicHighlight(h); hTmp.Intersect(overlap); AtomicHighlight oTmp = new AtomicHighlight(overlap); oTmp.Intersect(h); //System.Console.WriteLine(" Overlaps with {0}", oTmp); bool diffType = oTmp.Type != hTmp.Type; Drawer.HighlightType left, right, oleft, oright; hTmp.GetAbyssHighlights(out left, out right); oTmp.GetAbyssHighlights(out oleft, out oright); bool diffAbyss = (left != oleft) || (right != oright); if (diffType || diffAbyss) { //System.Console.Write(diffType?" DiffType> ":" DiffFlags> "); //System.Console.WriteLine(hTmp); RenderHighlight(hTmp); } } } } private void RenderCursor(IntervalTree atomicHighlights) { // find the kind of highlight the cursor was previously on // if we don't find an overlap this means that either // 1. the prev cursor position is not visible on the screen // 2. the prev cursor position is at or beyond the end of the file IList overlaps = atomicHighlights.SearchOverlap(new Util.Range(prevCursorOffset, prevCursorOffset)); AtomicHighlight h = null; // if we find an overlap create a highlight // to use to restore the prev position if (overlaps.Count > 0) { h = new AtomicHighlight(overlaps[0]); h.Start = prevCursorOffset; h.End = prevCursorOffset; } bool prevCursorBeyondEof = prevCursorOffset >= byteBuffer.Size; if (h != null) { RenderHighlight(h); } else if (prevCursorBeyondEof) { // case 2 foreach(Area a in areas) a.BlankOffset(prevCursorOffset); } if (selection.IsEmpty()) foreach(Area a in areas) a.RenderCursor(); } /// /// Render this area group. /// /// /// Whether to force a complete redraw of the group. /// /// /// If force is false this method tries to redraw as little /// as possible by drawing only the parts of the screen that /// have changed (eg when changing the selection) /// public void Render(bool force) { // sanity check if (byteBuffer == null) return; InitializeHighlights(); if (PreRenderEvent != null) PreRenderEvent(this); /* This breaks the RenderExtra() optimizations in OffsetArea and SeparatorArea // if we are forced to redraw but nothing // has changed, just redraw the previous atomic highlights if (force && !HasAnythingChanged()) { //System.Console.WriteLine("Not changed"); RenderAtomicHighlights(prevAtomicHighlights); return; }*/ // get the current atomic highlights IntervalTree atomicHighlights; // if atomic highlights have not changed, reuse them if (!force && !HasChanged(Changes.Highlights) && !HasChanged(Changes.Offset)) atomicHighlights = prevAtomicHighlights; else { //System.Console.WriteLine("Re-eval atomic highs"); atomicHighlights = GetAtomicHighlights(); } // if we are forced to redraw or the view has scrolled (the offset has changed) // redraw everything if (force || HasChanged(Changes.Offset)) { //System.Console.WriteLine("Scroll"); RenderAll(atomicHighlights); } // otherwise redraw only what is needed else if (HasChanged(Changes.Highlights)) { //System.Console.WriteLine("Diffs"); RenderHighlightDiffs(atomicHighlights); } if (HasChanged(Changes.Cursor)) { //System.Console.WriteLine("Cursor"); RenderCursor(atomicHighlights); } // update prevAtomicHighlights prevAtomicHighlights = atomicHighlights; ClearChanges(); } public delegate void PreRenderHandler(AreaGroup ag); public event PreRenderHandler PreRenderEvent; } } // end namespace bless-0.6.3/src/gui/areas/AsciiArea.cs000066400000000000000000000120241374060072200174460ustar00rootroot00000000000000// created on 6/15/2004 at 4:10 PM /* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using Gtk; using Gdk; using Bless.Gui.Drawers; using Bless.Plugins; namespace Bless.Gui.Areas.Plugins { public class AsciiAreaPlugin : AreaPlugin { public AsciiAreaPlugin() { name = "ascii"; author = "Alexandros Frantzis"; } public override Area CreateArea(AreaGroup ag) { return new AsciiArea(ag); } } ///An area that displays ascii public class AsciiArea : Area { public AsciiArea(AreaGroup ag) : base(ag) { type = "ascii"; dpb = 1; canFocus = true; } protected override void RenderRowNormal(int i, int p, int n, bool blank) { int rx = 0 + x; int ry = i * drawer.Height + y; long roffset = areaGroup.Offset + i * bpr + p; bool odd; Gdk.GC backEvenGC = drawer.GetBackgroundGC(Drawer.RowType.Even, Drawer.HighlightType.Normal); Gdk.GC backOddGC = drawer.GetBackgroundGC(Drawer.RowType.Odd, Drawer.HighlightType.Normal); // odd row? odd = (((roffset / bpr) % 2) == 1); if (blank == true) { if (odd) backPixmap.DrawRectangle(backOddGC, true, rx, ry, width, drawer.Height); else backPixmap.DrawRectangle(backEvenGC, true, rx, ry, width, drawer.Height); } Drawer.RowType rowType; if (odd) rowType = Drawer.RowType.Odd; else rowType = Drawer.RowType.Even; int pos = 0; while (true) { if (pos >= p) { //don't draw until we reach p drawer.DrawNormal(backEvenGC, backPixmap, rx, ry, areaGroup.GetCachedByte(roffset++), rowType, Drawer.ColumnType.Even); if (--n <= 0) break; } rx = rx + drawer.Width; pos++; } } protected override void RenderRowHighlight(int i, int p, int n, bool blank, Drawer.HighlightType ht) { int rx = 0 + x; int ry = i * drawer.Height + y; long roffset = areaGroup.Offset + i * bpr + p; bool odd; Gdk.GC backEvenGC = drawer.GetBackgroundGC(Drawer.RowType.Even, Drawer.HighlightType.Normal); Gdk.GC backOddGC = drawer.GetBackgroundGC(Drawer.RowType.Odd, Drawer.HighlightType.Normal); // odd row? odd = (((roffset / bpr) % 2) == 1); if (blank == true) { if (odd) backPixmap.DrawRectangle(backOddGC, true, rx, ry, width, drawer.Height); else backPixmap.DrawRectangle(backEvenGC, true, rx, ry, width, drawer.Height); } Drawer.RowType rowType; if (odd) rowType = Drawer.RowType.Odd; else rowType = Drawer.RowType.Even; int pos = 0; while (true) { if (pos >= p) { //don't draw until we reach p drawer.DrawHighlight(backEvenGC, backPixmap, rx, ry, areaGroup.GetCachedByte(roffset++), rowType, ht); if (--n <= 0) break; } rx = rx + drawer.Width; pos++; } } public override int CalcWidth(int n, bool force) { if (fixedBpr > 0 && n > fixedBpr && !force) return -1; else return n*drawer.Width; } public override void GetDisplayInfoByOffset(long off, out int orow, out int obyte, out int ox, out int oy) { orow = (int)((off - areaGroup.Offset) / bpr); obyte = (int)((off - areaGroup.Offset) % bpr); oy = orow * drawer.Height; ox = obyte * drawer.Width; } public override long GetOffsetByDisplayInfo(int x, int y, out int digit, out GetOffsetFlags flags) { flags = 0; int row = y / drawer.Height; int col = x / drawer.Width; long off = (row * bpr + col) + areaGroup.Offset; if (off >= areaGroup.Buffer.Size) flags |= GetOffsetFlags.Eof; digit = 0; return off; } public override bool HandleKey(Gdk.Key key, bool overwrite) { //System.Console.WriteLine("Ascii: {0}", key); byte[] ba = null; if (key >= Gdk.Key.space && key <= Gdk.Key.asciitilde) ba = new byte[]{(byte)key}; else if (key >= Gdk.Key.KP_0 && key <= Gdk.Key.KP_9) ba = new byte[]{(byte)(key - Gdk.Key.KP_0 + Gdk.Key.Key_0)}; if (ba != null) { if (areaGroup.CursorOffset == areaGroup.Buffer.Size) areaGroup.Buffer.Append(ba, 0, ba.LongLength); else if (overwrite == true) areaGroup.Buffer.Replace(areaGroup.CursorOffset, areaGroup.CursorOffset, ba); else if (overwrite == false) areaGroup.Buffer.Insert(areaGroup.CursorOffset, ba, 0, ba.LongLength); return true; } else return false; } public override void Realize() { Gtk.DrawingArea da = areaGroup.DrawingArea; drawer = new AsciiDrawer(da, drawerInformation); base.Realize(); } } }//namespace bless-0.6.3/src/gui/areas/BinaryArea.cs000066400000000000000000000052051374060072200176450ustar00rootroot00000000000000// created on 6/24/2004 at 2:32 PM /* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using Bless.Plugins; using Bless.Gui.Drawers; using Gtk; namespace Bless.Gui.Areas.Plugins { public class BinaryAreaPlugin : AreaPlugin { public BinaryAreaPlugin() { name = "binary"; author = "Alexandros Frantzis"; } public override Area CreateArea(AreaGroup ag) { return new BinaryArea(ag); } } ///An area that displays binary public class BinaryArea : GroupedArea { public BinaryArea(AreaGroup ag) : base(ag) { type = "binary"; dpb = 8; } public override bool HandleKey(Gdk.Key key, bool overwrite) { //System.Console.WriteLine("Binary: {0}", key); if (key == Gdk.Key.Key_0 || key == Gdk.Key.Key_1 || key == Gdk.Key.KP_0 || key == Gdk.Key.KP_1) { byte orig; // if we are after the end of the buffer, assume // a 0 byte if (areaGroup.CursorOffset == areaGroup.Buffer.Size || (overwrite == false && areaGroup.CursorDigit == 0)) orig = 0; else orig = areaGroup.Buffer[areaGroup.CursorOffset]; byte repl; if (key == Gdk.Key.Key_1 || key == Gdk.Key.KP_1 ) repl = (byte)((1 << (dpb - areaGroup.CursorDigit - 1)) | orig); else repl = (byte)((~(1 << (dpb - areaGroup.CursorDigit - 1))) & orig); byte[] ba = new byte[]{repl}; if (areaGroup.CursorOffset == areaGroup.Buffer.Size) areaGroup.Buffer.Append(ba, 0, ba.LongLength); else if (overwrite == false && areaGroup.CursorDigit == 0) areaGroup.Buffer.Insert(areaGroup.CursorOffset, ba, 0, ba.LongLength); else /*(if (overwrite==true || cursorDigit > 0)*/ areaGroup.Buffer.Replace(areaGroup.CursorOffset, areaGroup.CursorOffset, ba); return true; } else return false; } public override void Realize () { Gtk.DrawingArea da = areaGroup.DrawingArea; drawer = new BinaryDrawer(da, drawerInformation); base.Realize(); } } }//namespace bless-0.6.3/src/gui/areas/DecimalArea.cs000066400000000000000000000057231374060072200177640ustar00rootroot00000000000000// created on 7/1/2004 at 8:06 PM /* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using Bless.Plugins; using Bless.Gui.Drawers; using Gtk; namespace Bless.Gui.Areas.Plugins { public class DecimalAreaPlugin : AreaPlugin { public DecimalAreaPlugin() { name = "decimal"; author = "Alexandros Frantzis"; } public override Area CreateArea(AreaGroup ag) { return new DecimalArea(ag); } } ///An area that displays decimal public class DecimalArea : GroupedArea { public DecimalArea(AreaGroup ag) : base(ag) { type = "decimal"; dpb = 3; } public override bool HandleKey(Gdk.Key key, bool overwrite) { //System.Console.WriteLine("Decimal: {0}", key); if ((key >= Gdk.Key.Key_0 && key <= Gdk.Key.Key_9) || (key >= Gdk.Key.KP_0 && key <= Gdk.Key.KP_9)) { byte b; if (key >= Gdk.Key.Key_0 && key <= Gdk.Key.Key_9) b = (byte)(key - Gdk.Key.Key_0); else b = (byte)(key - Gdk.Key.KP_0); byte orig; // if we are after the end of the buffer, assume // a 0 byte if (areaGroup.CursorOffset == areaGroup.Buffer.Size || (overwrite == false && areaGroup.CursorDigit == 0)) orig = 0; else orig = areaGroup.Buffer[areaGroup.CursorOffset]; byte orig1 = (byte)(orig % 10); byte orig10 = (byte)((orig / 10) % 10); byte orig100 = (byte)((orig / 100) % 10); if (areaGroup.CursorDigit == 0) orig100 = b; else if (areaGroup.CursorDigit == 1) orig10 = b; else if (areaGroup.CursorDigit == 2) orig1 = b; int repl = orig100 * 100 + orig10 * 10 + orig1; if (repl > 255) return false; byte[] ba = new byte[]{(byte)repl}; if (areaGroup.CursorOffset == areaGroup.Buffer.Size) areaGroup.Buffer.Append(ba, 0, ba.LongLength); else if (overwrite == false && areaGroup.CursorDigit == 0) areaGroup.Buffer.Insert(areaGroup.CursorOffset, ba, 0, ba.LongLength); else /*(if (overwrite==true || areaGroup.CursorDigit > 0)*/ areaGroup.Buffer.Replace(areaGroup.CursorOffset, areaGroup.CursorOffset, ba); return true; } else return false; } public override void Realize () { Gtk.DrawingArea da = areaGroup.DrawingArea; drawer = new DecimalDrawer(da, drawerInformation); base.Realize(); } } }//namespace bless-0.6.3/src/gui/areas/GroupedArea.cs000066400000000000000000000126511374060072200200310ustar00rootroot00000000000000// created on 7/16/2004 at 7:54 PM /* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using Gtk; using Gdk; using Bless.Gui.Drawers; using System.Xml; namespace Bless.Gui.Areas.Plugins { ///An area that displays grouped bytes abstract public class GroupedArea : Area { int grouping; public GroupedArea(AreaGroup ag) : base(ag) { grouping = 1; canFocus = true; } public int Grouping { set { grouping = value; } get { return grouping; } } protected override void RenderRowNormal(int i, int p, int n, bool blank) { int rx = 0 + x; int ry = i * drawer.Height + y; long roffset = areaGroup.Offset + i * bpr + p; bool odd; Gdk.GC backEvenGC = drawer.GetBackgroundGC(Drawer.RowType.Even, Drawer.HighlightType.Normal); Gdk.GC backOddGC = drawer.GetBackgroundGC(Drawer.RowType.Odd, Drawer.HighlightType.Normal); // odd row? odd = (((roffset / bpr) % 2) == 1); if (blank == true) { if (odd) backPixmap.DrawRectangle(backOddGC, true, rx, ry, width, drawer.Height); else backPixmap.DrawRectangle(backEvenGC, true, rx, ry, width, drawer.Height); } Drawer.ColumnType colType; Drawer.RowType rowType; if (odd) rowType = Drawer.RowType.Odd; else rowType = Drawer.RowType.Even; int pos = 0; // draw bytes while (true) { if (pos >= p) { //don't draw until we reach p if ((pos / grouping) % 2 == 0) colType = Drawer.ColumnType.Even; else colType = Drawer.ColumnType.Odd; drawer.DrawNormal(backEvenGC, backPixmap, rx, ry, areaGroup.GetCachedByte(roffset++), rowType, colType); if (--n <= 0) break; } // space if necessary if (pos % grouping == grouping - 1) rx = rx + (dpb + 1) * drawer.Width; else rx = rx + dpb * drawer.Width; pos++; } } protected override void RenderRowHighlight(int i, int p, int n, bool blank, Drawer.HighlightType ht) { int rx = 0 + x; int ry = i * drawer.Height + y; long roffset = areaGroup.Offset + i * bpr + p; bool odd; Gdk.GC backEvenGC = drawer.GetBackgroundGC(Drawer.RowType.Even, Drawer.HighlightType.Normal); Gdk.GC backOddGC = drawer.GetBackgroundGC(Drawer.RowType.Odd, Drawer.HighlightType.Normal); // odd row? odd = (((roffset / bpr) % 2) == 1); if (blank == true) { if (odd) backPixmap.DrawRectangle(backOddGC, true, rx, ry, width, drawer.Height); else backPixmap.DrawRectangle(backEvenGC, true, rx, ry, width, drawer.Height); } Drawer.RowType rowType; if (odd) rowType = Drawer.RowType.Odd; else rowType = Drawer.RowType.Even; int pos = 0; // draw bytes while (true) { if (pos >= p) { //don't draw until we reach p drawer.DrawHighlight(backEvenGC, backPixmap, rx, ry, areaGroup.GetCachedByte(roffset++), rowType, ht); if (--n <= 0) break; } // space if necessary if (pos % grouping == grouping - 1) rx = rx + (dpb + 1) * drawer.Width; else rx = rx + dpb * drawer.Width; pos++; } } public override int CalcWidth(int n, bool force) { if (n == 0) return 0; if (fixedBpr > 0 && n > fixedBpr && !force) // must adhere to fixed length return -1; if (n % grouping != 0 && !force) // can't break the grouping return -1; int ngroups = n / grouping; int groupWidth = grouping * dpb * drawer.Width; return ngroups*groupWidth + (ngroups - 1)*drawer.Width; } public override void GetDisplayInfoByOffset(long off, out int orow, out int obyte, out int ox, out int oy) { orow = (int)((off - areaGroup.Offset) / bpr); obyte = (int)((off - areaGroup.Offset) % bpr); oy = orow * drawer.Height; int group = obyte / grouping; int groupOffset = obyte % grouping; ox = group * (grouping * dpb * drawer.Width + drawer.Width) + dpb * drawer.Width * groupOffset; } public override long GetOffsetByDisplayInfo(int x, int y, out int digit, out GetOffsetFlags flags) { flags = 0; int groupWidth = (grouping * dpb * drawer.Width + drawer.Width); int row = y / drawer.Height; int group = x / groupWidth; int groupByte = (x - group * groupWidth) / (dpb * drawer.Width); digit = (x - group * groupWidth - groupByte * dpb * drawer.Width) / drawer.Width; if (groupByte >= grouping) { groupByte = grouping - 1; flags |= GetOffsetFlags.Abyss; } long off = row * bpr + (group * grouping + groupByte) + areaGroup.Offset; if (off >= areaGroup.Buffer.Size) flags |= GetOffsetFlags.Eof; return off; } public override void Configure(XmlNode parentNode) { base.Configure(parentNode); XmlNodeList childNodes = parentNode.ChildNodes; foreach(XmlNode node in childNodes) { if (node.Name == "grouping") this.Grouping = Convert.ToInt32(node.InnerText); } } }// end GroupedArea }//end namespacebless-0.6.3/src/gui/areas/HexArea.cs000066400000000000000000000063671374060072200171570ustar00rootroot00000000000000// created on 6/15/2004 at 4:10 PM /* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System.Xml; using Bless.Plugins; using Bless.Gui.Drawers; using Gtk; namespace Bless.Gui.Areas.Plugins { public class HexAreaPlugin : AreaPlugin { public HexAreaPlugin() { name = "hexadecimal"; author = "Alexandros Frantzis"; } public override Area CreateArea(AreaGroup ag) { return new HexArea(ag); } } ///An area that displays hexadecimal public class HexArea : GroupedArea { public HexArea(AreaGroup ag) : base(ag) { type = "hexadecimal"; dpb = 2; } private int KeyToHex(Gdk.Key key) { if (key >= Gdk.Key.Key_0 && key <= Gdk.Key.Key_9) return key - Gdk.Key.Key_0; else if (key >= Gdk.Key.A && key <= Gdk.Key.F) return key - Gdk.Key.A + 10; else if (key >= Gdk.Key.a && key <= Gdk.Key.f) return key - Gdk.Key.a + 10; else if (key >= Gdk.Key.KP_0 && key <= Gdk.Key.KP_9) return key - Gdk.Key.KP_0; else return -1; } public override bool HandleKey(Gdk.Key key, bool overwrite) { int hex = KeyToHex(key); if (hex != -1) { byte b = (byte)hex; byte orig; // if we are after the end of the buffer, assume // a 0 byte if (areaGroup.CursorOffset == areaGroup.Buffer.Size || (overwrite == false && areaGroup.CursorDigit == 0)) orig = 0; else orig = areaGroup.Buffer[areaGroup.CursorOffset]; byte orig1 = (byte)(orig % 16); byte orig16 = (byte)((orig / 16) % 16); if (areaGroup.CursorDigit == 0) orig16 = b; else if (areaGroup.CursorDigit == 1) orig1 = b; byte repl = (byte)(orig16 * 16 + orig1); byte[] ba = new byte[]{repl}; if (areaGroup.CursorOffset == areaGroup.Buffer.Size) areaGroup.Buffer.Append(ba, 0, ba.LongLength); else if (overwrite == false && areaGroup.CursorDigit == 0) areaGroup.Buffer.Insert(areaGroup.CursorOffset, ba, 0, ba.LongLength); else /*(if (overwrite==true || areaGroup.CursorDigit > 0)*/ areaGroup.Buffer.Replace(areaGroup.CursorOffset, areaGroup.CursorOffset, ba); return true; } else return false; } public override void Configure(XmlNode parentNode) { base.Configure(parentNode); XmlNodeList childNodes = parentNode.ChildNodes; foreach(XmlNode node in childNodes) { if (node.Name == "case") drawerInformation.Uppercase = (node.InnerText == "upper"); } } public override void Realize () { Gtk.DrawingArea da = areaGroup.DrawingArea; drawer = new HexDrawer(da, drawerInformation); base.Realize(); } } }//namespace bless-0.6.3/src/gui/areas/Highlight.cs000066400000000000000000000037731374060072200175470ustar00rootroot00000000000000// created on 19/3/2008 at 6:14 PM /* * Copyright (c) 2008, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.Collections.Generic; using Bless.Util; using Bless.Gui.Drawers; namespace Bless.Gui.Areas { public class Highlight : Util.Range, IEquatable { protected Drawer.HighlightType type; public Drawer.HighlightType Type { get { return type; } } public Highlight() : base() { type = Drawer.HighlightType.Normal; } public Highlight(Drawer.HighlightType ht) : base() { type = ht; } public Highlight(IRange r, Drawer.HighlightType ht) : base(r) { type = ht; } public Highlight(long start, long end, Drawer.HighlightType ht) : base(start, end) { type = ht; } public Highlight(Highlight h) : this(h, h.Type) { } public bool Equals(Highlight h) { return this.Start == h.Start && this.End == h.End && this.Type == h.Type; } public override bool Equals(object obj) { Highlight h = obj as Highlight; if (h != null) return Equals(h); else return false; } public override int GetHashCode() { return (start.GetHashCode() ^ end.GetHashCode() ^ type.GetHashCode()); } public override string ToString() { return base.ToString() + " Type: " + type; } } } // end namespacebless-0.6.3/src/gui/areas/OctalArea.cs000066400000000000000000000056611374060072200174710ustar00rootroot00000000000000// created on 7/1/2004 at 8:39 PM /* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using Bless.Plugins; using Bless.Gui.Drawers; using Gtk; namespace Bless.Gui.Areas.Plugins { public class OctalAreaPlugin : AreaPlugin { public OctalAreaPlugin() { name = "octal"; author = "Alexandros Frantzis"; } public override Area CreateArea(AreaGroup ag) { return new OctalArea(ag); } } ///An area that displays octal public class OctalArea : GroupedArea { public OctalArea(AreaGroup ag) : base(ag) { type = "octal"; dpb = 3; } public override bool HandleKey(Gdk.Key key, bool overwrite) { //System.Console.WriteLine("Octal: {0}", key); if (key >= Gdk.Key.Key_0 && key <= Gdk.Key.Key_7 || (key >= Gdk.Key.KP_0 && key <= Gdk.Key.KP_7)) { byte b; if (key >= Gdk.Key.Key_0 && key <= Gdk.Key.Key_7) b = (byte)(key - Gdk.Key.Key_0); else b = (byte)(key - Gdk.Key.KP_0); byte orig; // if we are after the end of the buffer, assume // a 0 byte if (areaGroup.CursorOffset == areaGroup.Buffer.Size || (overwrite == false && areaGroup.CursorDigit == 0)) orig = 0; else orig = areaGroup.Buffer[areaGroup.CursorOffset]; byte orig1 = (byte)(orig % 8); byte orig8 = (byte)((orig / 8) % 8); byte orig64 = (byte)((orig / 64) % 8); if (areaGroup.CursorDigit == 0) orig64 = b; else if (areaGroup.CursorDigit == 1) orig8 = b; else if (areaGroup.CursorDigit == 2) orig1 = b; int repl = orig64 * 64 + orig8 * 8 + orig1; if (repl > 255) return false; byte[] ba = new byte[]{(byte)repl}; if (areaGroup.CursorOffset == areaGroup.Buffer.Size) areaGroup.Buffer.Append(ba, 0, ba.LongLength); else if (overwrite == false && areaGroup.CursorDigit == 0) areaGroup.Buffer.Insert(areaGroup.CursorOffset, ba, 0, ba.LongLength); else /*(if (overwrite==true || areaGroup.CursorDigit > 0)*/ areaGroup.Buffer.Replace(areaGroup.CursorOffset, areaGroup.CursorOffset, ba); return true; } else return false; } public override void Realize () { Gtk.DrawingArea da = areaGroup.DrawingArea; drawer = new OctalDrawer(da, drawerInformation); base.Realize(); } } }//namespace bless-0.6.3/src/gui/areas/OffsetArea.cs000066400000000000000000000106441374060072200176520ustar00rootroot00000000000000// created on 6/14/2004 at 11:05 PM /* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using Gtk; using Gdk; using Bless.Gui.Drawers; using Bless.Util; using System.Xml; using Bless.Plugins; namespace Bless.Gui.Areas.Plugins { public class OffsetAreaPlugin : AreaPlugin { public OffsetAreaPlugin() { name = "offset"; author = "Alexandros Frantzis"; } public override Area CreateArea(AreaGroup ag) { return new OffsetArea(ag); } } ///An area that display the offsets public class OffsetArea : Area { int bytes; public int Bytes { get { return bytes; } set { bytes = value; } } public OffsetArea(AreaGroup ag) : base(ag) { type = "offset"; bytes = 4; } protected override void RenderExtra() { if (bpr <= 0) return; int nrows = height / drawer.Height; long bleft = nrows * bpr; int rfull = 0; int blast = 0; if (bleft + areaGroup.Offset > areaGroup.Buffer.Size) bleft = areaGroup.Buffer.Size - areaGroup.Offset + 1; // calculate number of full rows // and number of bytes in last (non-full) rfull = (int)(bleft / bpr); blast = (int)(bleft % bpr); if (blast > 0) rfull++; for (int i = 0; i < rfull; i++) RenderRowNormal(i, 0, bpr, true); } protected override void RenderHighlight(Highlight h, Drawer.HighlightType left, Drawer.HighlightType right) { } protected override void RenderRowNormal(int i, int p, int n, bool blank) { int rx = (bytes - 1) * 2 * drawer.Width + x; int ry = i * drawer.Height + y; long roffset = areaGroup.Offset + i * bpr; bool odd; Gdk.GC backEvenGC = drawer.GetBackgroundGC(Drawer.RowType.Even, Drawer.HighlightType.Normal); Gdk.GC backOddGC = drawer.GetBackgroundGC(Drawer.RowType.Odd, Drawer.HighlightType.Normal); // odd row? odd = (((roffset / bpr) % 2) == 1); if (blank == true) { if (odd) backPixmap.DrawRectangle(backOddGC, true, x, ry, width, drawer.Height); else backPixmap.DrawRectangle(backEvenGC, true, x, ry, width, drawer.Height); } Drawer.RowType rowType; if (odd) rowType = Drawer.RowType.Odd; else rowType = Drawer.RowType.Even; // if nothing to draw return if (n == 0) return; // draw offsets for (int j = 0; j < bytes; j++) { drawer.DrawNormal(backEvenGC, backPixmap, rx, ry, (byte)(roffset & 0xff), rowType, Drawer.ColumnType.Even); roffset = roffset >> 8; rx = rx - 2 * drawer.Width; } } protected override void RenderRowHighlight(int i, int p, int n, bool blank, Drawer.HighlightType ht) { RenderRowNormal(i, p, n, blank); } public override int CalcWidth(int n, bool force) { return 2*bytes*drawer.Width; } public override void GetDisplayInfoByOffset(long off, out int orow, out int obyte, out int ox, out int oy) { orow = (int)((off - areaGroup.Offset) / bpr); obyte = (int)((off - areaGroup.Offset) % bpr); oy = orow * drawer.Height; ox = 0; } public override long GetOffsetByDisplayInfo(int x, int y, out int digit, out GetOffsetFlags flags) { flags = 0; int row = y / drawer.Height; long off = row * bpr + areaGroup.Offset; if (off >= areaGroup.Buffer.Size) flags |= GetOffsetFlags.Eof; digit = 0; return off; } public override void Configure(XmlNode parentNode) { base.Configure(parentNode); XmlNodeList childNodes = parentNode.ChildNodes; foreach(XmlNode node in childNodes) { if (node.Name == "case") drawerInformation.Uppercase = (node.InnerText == "upper"); if (node.Name == "bytes") this.Bytes = Convert.ToInt32(node.InnerText); } } public override void Realize () { Gtk.DrawingArea da = areaGroup.DrawingArea; drawer = new HexDrawer(da, drawerInformation); base.Realize(); } } }//namespace bless-0.6.3/src/gui/areas/SeparatorArea.cs000066400000000000000000000064451374060072200203700ustar00rootroot00000000000000// created on 6/18/2004 at 7:46 PM /* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using Gtk; using Gdk; using Bless.Gui.Drawers; using Bless.Util; using Bless.Plugins; namespace Bless.Gui.Areas.Plugins { public class SeparatorAreaPlugin : AreaPlugin { public SeparatorAreaPlugin() { name = "separator"; author = "Alexandros Frantzis"; } public override Area CreateArea(AreaGroup ag) { return new SeparatorArea(ag); } } ///An area that contains a vertical separator line public class SeparatorArea : Area { Gdk.GC lineGC; public SeparatorArea(AreaGroup ag) : base(ag) { type = "separator"; } public override void Realize() { Gtk.DrawingArea da = areaGroup.DrawingArea; drawer = new DummyDrawer(da, drawerInformation); lineGC = new Gdk.GC(da.GdkWindow); lineGC.RgbFgColor = drawer.Info.fgNormal[(int)Drawer.RowType.Even, (int)Drawer.ColumnType.Even].GdkColor; base.Realize(); } protected override void RenderHighlight(Highlight h, Drawer.HighlightType left, Drawer.HighlightType right) { } protected override void RenderRowNormal(int i, int p, int n, bool blank) { } protected override void RenderRowHighlight(int i, int p, int n, bool blank, Drawer.HighlightType ht) { } protected override void RenderExtra() { if (isAreaRealized == false) return; int nrows = height / drawer.Height; long bleft = nrows * bpr; int rfull = 0; int blast = 0; if (bpr > 0) { if (bleft + areaGroup.Offset > areaGroup.Buffer.Size) bleft = areaGroup.Buffer.Size - areaGroup.Offset + 1; // calculate number of full rows // and number of bytes in last (non-full) rfull = (int)(bleft / bpr); blast = (int)(bleft % bpr); if (blast != 0) rfull++; } if (rfull == 0) return; // draw seperator backPixmap.DrawLine(lineGC, x + drawer.Width / 2, 0, x + drawer.Width / 2, drawer.Height*rfull); } public override int CalcWidth(int n, bool force) { return drawer.Width; } public override void GetDisplayInfoByOffset(long off, out int orow, out int obyte, out int ox, out int oy) { orow = (int)((off - areaGroup.Offset) / bpr); obyte = (int)((off - areaGroup.Offset) % bpr); oy = orow * drawer.Height; ox = 0; } public override long GetOffsetByDisplayInfo(int x, int y, out int digit, out GetOffsetFlags flags) { flags = 0; int row = y / drawer.Height; long off = row * bpr + areaGroup.Offset; if (off >= areaGroup.Buffer.Size) flags |= GetOffsetFlags.Eof; digit = 0; return off; } } }//namespace bless-0.6.3/src/gui/dialogs/000077500000000000000000000000001374060072200156265ustar00rootroot00000000000000bless-0.6.3/src/gui/dialogs/AboutDialog.cs000066400000000000000000000027511374060072200203540ustar00rootroot00000000000000// created on 1/21/2005 at 2:32 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using Gtk; using Gdk; using Bless.Util; using Mono.Unix; namespace Bless.Gui.Dialogs { public class AboutDialog: Gtk.AboutDialog { public AboutDialog() { Artists = new string[] {"Michael Iatrou"}; Authors = new string[] {"Alexandros Frantzis"}; Copyright = Catalog.GetString("Copyright 2004 - 2020 Alexandros Frantzis and contributors"); ProgramName = "Bless"; Version = ConfigureDefines.VERSION; Comments = Catalog.GetString("Bless is a Hex Editor for Gtk#"); Website = "https://github.com/afrantzis/bless"; Logo = new Gdk.Pixbuf(FileResourcePath.GetDataPath("bless-about.png")); } } } //end namespace bless-0.6.3/src/gui/dialogs/Alert.cs000066400000000000000000000043721374060072200172320ustar00rootroot00000000000000// created on 7/28/2004 at 7:09 PM /* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using Gtk; namespace Bless.Gui.Dialogs { ///An alert dialog box as recommended in the Gnome HIG abstract public class Alert : Gtk.Dialog { protected Gtk.HBox hbox; protected Gtk.VBox labelBox; protected Gtk.Image image; protected Gtk.Label labelPrimary; protected Gtk.Label labelSecondary; public Alert(string primary, string secondary, Gtk.Window parent) : base("", parent, Gtk.DialogFlags.DestroyWithParent) { // set-up alert this.Modal = true; //this.TypeHint=Gdk.WindowTypeHint.Utility; this.BorderWidth = 6; this.HasSeparator = false; this.Resizable = false; this.VBox.Spacing = 12; hbox = new Gtk.HBox(); hbox.Spacing = 12; hbox.BorderWidth = 6; this.VBox.Add(hbox); // set-up image image = new Gtk.Image(); image.Yalign = 0.0F; hbox.Add(image); // set-up labels labelPrimary = new Gtk.Label(); labelPrimary.Yalign = 0.0F; labelPrimary.Xalign = 0.0F; labelPrimary.UseMarkup = true; labelPrimary.Wrap = true; labelSecondary = new Gtk.Label(); labelSecondary.Yalign = 0.0F; labelSecondary.Xalign = 0.0F; labelSecondary.UseMarkup = true; labelSecondary.Wrap = true; labelPrimary.Markup = "" + primary + ""; labelSecondary.Markup = "\n" + secondary; labelBox = new VBox(); labelBox.Add(labelPrimary); labelBox.Add(labelSecondary); hbox.Add(labelBox); } } }bless-0.6.3/src/gui/dialogs/ErrorAlert.cs000066400000000000000000000024161374060072200202410ustar00rootroot00000000000000// created on 7/28/2004 at 7:33 PM /* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using Gtk; namespace Bless.Gui.Dialogs { ///An alert dialog box as recommended in the Gnome HIG public class ErrorAlert : Alert { public ErrorAlert(string primary, string secondary, Gtk.Window parent) : base(primary, secondary, parent) { image.SetFromStock(Gtk.Stock.DialogError, Gtk.IconSize.Dialog); this.AddButton(Gtk.Stock.Ok, ResponseType.Ok); this.ShowAll(); } } }bless-0.6.3/src/gui/dialogs/ExportDialog.cs000066400000000000000000000244101374060072200205570ustar00rootroot00000000000000// created on 12/4/2006 at 1:25 AM /* * Copyright (c) 2006, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.Threading; using System.IO; using Gtk; using Bless.Plugins; using Bless.Tools.Export; using Bless.Gui; using Bless.Util; using Bless.Buffers; using Mono.Unix; namespace Bless.Gui.Dialogs { public class ExportDialog : Dialog { PluginManager pluginManager; DataBook dataBook; Gtk.Window mainWindow; [Gtk.Builder.Object] Gtk.VBox ExportDialogVBox; [Gtk.Builder.Object] Gtk.ComboBox ExportAsCombo; [Gtk.Builder.Object] Gtk.ComboBoxEntry ExportPatternComboEntry; [Gtk.Builder.Object] Gtk.ProgressBar ExportProgressBar; [Gtk.Builder.Object] Gtk.Entry ExportFileEntry; [Gtk.Builder.Object] Gtk.RadioButton WholeFileRadio; [Gtk.Builder.Object] Gtk.RadioButton CurrentSelectionRadio; [Gtk.Builder.Object] Gtk.RadioButton RangeRadio; [Gtk.Builder.Object] Gtk.Entry RangeFromEntry; [Gtk.Builder.Object] Gtk.Entry RangeToEntry; [Gtk.Builder.Object] Gtk.HBox ProgressHBox; Gtk.Button CloseButton; Gtk.Button ExportButton; AutoResetEvent exportFinishedEvent; readonly public object LockObj = new object(); bool cancelClicked; public ExportDialog(DataBook db, Gtk.Window mw) : base(Catalog.GetString("Export Bytes"), null, 0) { Gtk.Builder builder = new Gtk.Builder(); builder.AddFromFile(FileResourcePath.GetDataPath("ui", "ExportDialog.ui")); builder.Autoconnect(this); dataBook = db; mainWindow = mw; pluginManager = PluginManager.GetForType(typeof(ExportPlugin)); // initialize plugins if we have to if (pluginManager == null) { PluginManager.AddForType(typeof(ExportPlugin), new object[0]); pluginManager = PluginManager.GetForType(typeof(ExportPlugin)); } exportFinishedEvent = new AutoResetEvent(false); SetupExportPlugins(); ExportPatternComboEntry.Model = new ListStore (typeof (string)); ExportPatternComboEntry.TextColumn = 0; LoadFromPatternFile((ListStore)ExportPatternComboEntry.Model); ProgressHBox.Visible = false; cancelClicked = false; this.Modal = false; this.BorderWidth = 6; this.HasSeparator = false; CloseButton = (Gtk.Button)this.AddButton(Gtk.Stock.Close, ResponseType.Close); ExportButton = (Gtk.Button)this.AddButton(Catalog.GetString("Export"), ResponseType.Ok); this.Response += new ResponseHandler(OnDialogResponse); this.VBox.Add(ExportDialogVBox); } private void SetupExportPlugins() { ListStore model = new ListStore(typeof(string), typeof(ExportPlugin)); foreach(ExportPlugin plugin in pluginManager.Plugins) { model.AppendValues(plugin.Description, plugin); } Gtk.CellRenderer renderer = new Gtk.CellRendererText(); ExportAsCombo.PackStart(renderer, false); ExportAsCombo.AddAttribute(renderer, "text", 0); ExportAsCombo.Model = model; ExportAsCombo.Active = 0; } private Util.Range GetCurrentRange(DataView dv) { if (WholeFileRadio.Active == true) return new Util.Range(0, dv.Buffer.Size - 1); else if (CurrentSelectionRadio.Active == true) return dv.Selection; else if (RangeRadio.Active == true) return new Util.Range(BaseConverter.Parse(RangeFromEntry.Text), BaseConverter.Parse(RangeToEntry.Text)); return new Util.Range(); } private void OnSelectFileButtonClicked(object o, EventArgs args) { FileChooserDialog fcd = new FileChooserDialog(Catalog.GetString("Select file"), mainWindow, FileChooserAction.Save, Catalog.GetString("Cancel"), ResponseType.Cancel, Catalog.GetString("Select"), ResponseType.Accept); if ((ResponseType)fcd.Run() == ResponseType.Accept) ExportFileEntry.Text = fcd.Filename; fcd.Destroy(); } private void OnRangeRadioToggled(object o, EventArgs args) { RangeFromEntry.Sensitive = RangeRadio.Active; RangeToEntry.Sensitive = RangeRadio.Active; } private void OnExportCancelClicked(object o, EventArgs args) { cancelClicked = true; } private void OnDeletePatternButtonClicked(object o, EventArgs args) { string pattern = ExportPatternComboEntry.Entry.Text; if (pattern != "") { ListStore ls = (ListStore)ExportPatternComboEntry.Model; TreeIter iter; int index = FindPattern(ls, pattern, out iter); if (index >= 0) { ls.Remove(ref iter); UpdatePatternFile(ls); } } } private void OnSavePatternButtonClicked(object o, EventArgs args) { string pattern = ExportPatternComboEntry.Entry.Text; if (pattern != "") { ListStore ls = (ListStore)ExportPatternComboEntry.Model; TreeIter iter; if (FindPattern(ls, pattern, out iter) < 0) { ls.AppendValues(pattern); UpdatePatternFile(ls); } } } private int FindPattern(ListStore ls, string pattern, out TreeIter ti) { ti = new TreeIter(); TreeIter iter; if (ls.GetIterFirst(out iter) == false) return -1; string val; int i = 0; while ((val = (ls.GetValue(iter, 0) as string)) != null) { if (pattern == val) { ti = iter; return i; } ls.IterNext(ref iter); i++; } return -1; } private FileStream GetPatternFile(FileMode mode, FileAccess access) { string patternDir = FileResourcePath.GetUserPath(); FileStream fs = new FileStream(System.IO.Path.Combine(patternDir, "export_patterns"), mode, access); return fs; } private void LoadFromPatternFile(ListStore ls) { StreamReader reader; try { FileStream fs = GetPatternFile(FileMode.Open, FileAccess.Read); reader = new StreamReader(fs); } catch (Exception e) { System.Console.WriteLine(e.Message); return; } string pattern; while ((pattern = reader.ReadLine()) != null) { ls.AppendValues(pattern); } reader.BaseStream.Close(); } private void UpdatePatternFile(ListStore ls) { StreamWriter writer; try { FileStream fs = GetPatternFile(FileMode.Create, FileAccess.Write); writer = new StreamWriter(fs); } catch (Exception e) { System.Console.WriteLine(e.Message); return; } foreach (object[] row in ls) writer.WriteLine(row[0] as string); writer.Flush(); writer.BaseStream.Close(); } private IAsyncResult BeginExport(IExporter exporter, IBuffer buf, long start, long end) { exportFinishedEvent.Reset(); ExportOperation eo = new ExportOperation(exporter, buf, start, end, ExportProgressCallback, OnExportFinished); CloseButton.Sensitive = false; ExportButton.Sensitive = false; // start export thread Thread exportThread = new Thread(eo.OperationThread); exportThread.IsBackground = true; exportThread.Start(); return new ThreadedAsyncResult(eo, exportFinishedEvent, false); } private void OnExportFinished(IAsyncResult ar) { lock (LockObj) { ExportOperation eo = (ExportOperation)ar.AsyncState; if (eo.Result == ExportOperation.OperationResult.Finished) { Services.UI.Info.DisplayMessage(string.Format(Catalog.GetString("Exported data to '{0}'"), (eo.Exporter.Builder.OutputStream as FileStream).Name)); this.Hide(); } else if (eo.Result == ExportOperation.OperationResult.CaughtException) { ErrorAlert ea; if (eo.ThreadException.GetType() == typeof(FormatException)) ea = new ErrorAlert(Catalog.GetString("Export Pattern Error"), eo.ThreadException.Message, mainWindow); else ea = new ErrorAlert(Catalog.GetString("Exporting Error"), eo.ThreadException.Message, mainWindow); ea.Run(); ea.Destroy(); } if (eo.Exporter.Builder.OutputStream != null) eo.Exporter.Builder.OutputStream.Close(); CloseButton.Sensitive = true; ExportButton.Sensitive = true; } } private bool ExportProgressCallback(object o, ProgressAction action) { if (action == ProgressAction.Hide) { ProgressHBox.Visible = false; return false; } else if (action == ProgressAction.Show) { ProgressHBox.Visible = true; return false; } if ((double)o > 1.0) o = 1.0; ExportProgressBar.Fraction = (double)o; return cancelClicked; } void OnDialogResponse(object o, Gtk.ResponseArgs args) { lock (LockObj) { if (args.ResponseId == ResponseType.Ok && dataBook != null && dataBook.NPages > 0) { DataView dv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; IExportBuilder builder = null; TreeIter iter; ExportAsCombo.GetActiveIter(out iter); ExportPlugin plugin = (ExportPlugin) ExportAsCombo.Model.GetValue(iter, 1); Util.Range range; try { range = GetCurrentRange(dv); } catch (FormatException ex) { ErrorAlert ea = new ErrorAlert(Catalog.GetString("Error in custom range"), ex.Message, mainWindow); ea.Run(); ea.Destroy(); return; } Util.Range bufferRange; if (dv.Buffer.Size == 0) bufferRange = new Util.Range(); else bufferRange = new Util.Range(0, dv.Buffer.Size - 1); if (!bufferRange.Contains(range.Start) || !bufferRange.Contains(range.End)) { ErrorAlert ea = new ErrorAlert(Catalog.GetString("Error in range"), Catalog.GetString("Range is out of file's limits"), mainWindow); ea.Run(); ea.Destroy(); return; } Stream stream = null; try { stream = new FileStream(ExportFileEntry.Text, FileMode.Create, FileAccess.Write); builder = plugin.CreateBuilder(stream); InterpretedPatternExporter exporter = new InterpretedPatternExporter(builder); exporter.Pattern = ExportPatternComboEntry.Entry.Text; cancelClicked = false; BeginExport(exporter, dv.Buffer, range.Start, range.End); } catch (Exception ex) { if (stream != null) stream.Close(); ErrorAlert ea = new ErrorAlert(Catalog.GetString("Error saving to file"), ex.Message, mainWindow); ea.Run(); ea.Destroy(); return; } } else if (args.ResponseId == ResponseType.Close) this.Hide(); } } } } // end namespace bless-0.6.3/src/gui/dialogs/FileOverwriteAlert.cs000066400000000000000000000031551374060072200217370ustar00rootroot00000000000000// created on 10/28/2004 at 10:55 AM /* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using Gtk; using Mono.Unix; namespace Bless.Gui.Dialogs { ///An alert dialog box as recommended in the Gnome HIG public class FileOverwriteAlert : Alert { static readonly string msg1 = Catalog.GetString("A file named '{0}' already exists"); static readonly string msg2 = Catalog.GetString("Do you want to replace it with the one you are saving?"); public FileOverwriteAlert(string primary, Gtk.Window parent) : base(string.Format(msg1, primary), msg2, parent) { image.SetFromStock(Gtk.Stock.DialogWarning, Gtk.IconSize.Dialog); this.AddButton(Gtk.Stock.Cancel, ResponseType.Cancel); this.AddButton(Catalog.GetString("Replace"), ResponseType.Ok); this.DefaultResponse = ResponseType.Cancel; this.ShowAll(); } } }bless-0.6.3/src/gui/dialogs/InformationAlert.cs000066400000000000000000000024461374060072200214400ustar00rootroot00000000000000// created on 2/5/2005 at 4:21 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using Gtk; namespace Bless.Gui.Dialogs { ///An alert dialog box as recommended in the Gnome HIG public class InformationAlert : Alert { public InformationAlert(string primary, string secondary, Gtk.Window parent) : base(primary, secondary, parent) { image.SetFromStock(Gtk.Stock.DialogInfo, Gtk.IconSize.Dialog); this.AddButton(Gtk.Stock.Ok, ResponseType.Ok); this.ShowAll(); } } } // namespace bless-0.6.3/src/gui/dialogs/LayoutSelectionDialog.cs000066400000000000000000000124051374060072200224220ustar00rootroot00000000000000// created on 6/28/2004 at 12:58 PM /* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.IO; using Gtk; using Bless.Gui.Areas; using Bless.Buffers; using Bless.Util; using Mono.Unix; namespace Bless.Gui.Dialogs { /// /// A dialog that lets the user select one of the available layouts /// public class LayoutSelectionDialog : Dialog { DataBook dataBook; DataView dataPreview; [Gtk.Builder.Object] Gtk.TreeView LayoutList; [Gtk.Builder.Object] Gtk.Frame PreviewFrame; [Gtk.Builder.Object] Gtk.Paned LayoutSelectionPaned; TreeIter selectedLayoutIter; string selectedLayout; string layoutDir; public string SelectedLayout { get { return selectedLayout; } } enum LayoutColumn { Filename, Path } public LayoutSelectionDialog(DataBook db) : base(Catalog.GetString("Select Layout"), null, 0) { Gtk.Builder builder = new Gtk.Builder(); builder.AddFromFile(FileResourcePath.GetDataPath("ui", "LayoutSelectionDialog.ui")); builder.Autoconnect(this); dataBook = db; // create the preview area dataPreview = new DataView(); ByteBuffer bb = new ByteBuffer(); bb.Append(new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, 0, 16); bb.Append(new byte[]{16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}, 0, 16); dataPreview.Buffer = bb; PreviewFrame.Add(dataPreview.Display); PreviewFrame.ShowAll(); layoutDir = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "bless"); layoutDir = System.IO.Path.Combine(layoutDir, "layouts"); // Initialize list PopulateLayoutList(); this.DefaultWidth = 600; this.DefaultHeight = 300; this.Modal = false; this.BorderWidth = 6; this.HasSeparator = false; this.AddButton(Gtk.Stock.Close, ResponseType.Close); this.AddButton(Gtk.Stock.Ok, ResponseType.Ok); this.Response += new ResponseHandler(OnDialogResponse); this.VBox.Add(LayoutSelectionPaned); } ///Populate the layout list void PopulateLayoutList() { // specify the column types TreeStore ts = new TreeStore(typeof(string), typeof(string)); TreeIter ti = ts.AppendValues(Catalog.GetString("System-wide Layouts"), string.Empty); // fill list from bless data dir string dataDir = FileResourcePath.GetDataPath("data"); if (Directory.Exists(dataDir)) { string[] files = Directory.GetFiles(dataDir, "*.layout"); foreach (string s in files) { ts.AppendValues(ti, System.IO.Path.GetFileName(s), s); } } ti = ts.AppendValues(Catalog.GetString("User Layouts"), string.Empty); // fill list from user layout dir if (Directory.Exists(layoutDir)) { string[] files = Directory.GetFiles(layoutDir, "*.layout"); foreach (string s in files) { ts.AppendValues(ti, System.IO.Path.GetFileName(s), s); } } // Create the treeview LayoutList.Model = ts; LayoutList.AppendColumn("Layout", new CellRendererText (), "text", (int)LayoutColumn.Filename); LayoutList.ExpandAll(); LayoutList.Selection.Changed += OnLayoutListSelectionChanged; } ///Handle list selection changed event public void OnLayoutListSelectionChanged (object o, EventArgs args) { TreeSelection sel = (TreeSelection)o; TreeModel tm; TreeIter ti; if (sel.GetSelected(out tm, out ti)) { string val = (string) tm.GetValue (ti, (int)LayoutColumn.Path); // if there is not path, it means user clicked on a header row if (val == string.Empty) { if (selectedLayout != null) sel.SelectIter(selectedLayoutIter); else sel.UnselectIter(ti); return; } // try to load layout from file try { dataPreview.Display.Layout = new Layout(val); selectedLayoutIter = ti; selectedLayout = val; } catch (System.Xml.XmlException ex) { string msg = string.Format(Catalog.GetString("Error parsing layout file '{0}'"), val); ErrorAlert ea = new ErrorAlert(msg, ex.Message, this); ea.Run(); ea.Destroy(); if (selectedLayout != null) sel.SelectIter(selectedLayoutIter); else sel.UnselectIter(ti); } finally { dataPreview.Display.Redraw(); } } } void OnDialogResponse(object o, Gtk.ResponseArgs args) { if (args.ResponseId == ResponseType.Ok && selectedLayout != null) { // get current dataview if (dataBook != null && dataBook.NPages > 0) { DataView dv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; dv.Display.Layout = new Layout(selectedLayout); } } // dispose preview Area pixmaps dataPreview.Cleanup(); this.Destroy(); } } }//namespace bless-0.6.3/src/gui/dialogs/PreferencesDialog.cs000066400000000000000000000342171374060072200215450ustar00rootroot00000000000000// created on 6/3/2005 at 12:21 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.IO; using System.Collections.Generic; using Gtk; using Bless.Tools; using Bless.Util; using Mono.Unix; using Bless.Plugins; namespace Bless.Gui.Dialogs { /// /// A dialog that lets user choose preferences for Bless /// public class PreferencesDialog : Dialog { Window mainWindow; GeneralPreferences generalPreferences; SessionPreferences sessionPreferences; UndoPreferences undoPreferences; TreeIter selectedIter; [Gtk.Builder.Object] Paned PreferencesPaned; [Gtk.Builder.Object] TreeView PreferencesTreeView; public PreferencesDialog(Window parent) : base (Catalog.GetString("Bless Preferences"), parent, DialogFlags.DestroyWithParent) { Gtk.Builder builder = new Gtk.Builder(); builder.AddFromFile(FileResourcePath.GetDataPath("ui", "PreferencesDialog.ui")); builder.Autoconnect(this); mainWindow = parent; generalPreferences = new GeneralPreferences(mainWindow); sessionPreferences = new SessionPreferences(mainWindow); undoPreferences = new UndoPreferences(mainWindow); LoadPreferencesTreeView(); this.Modal = false; this.TransientFor = parent; this.BorderWidth = 6; this.AddButton(Gtk.Stock.Close, ResponseType.Close); this.Response += new ResponseHandler(OnDialogResponse); this.VBox.Add(PreferencesPaned); this.VBox.ShowAll(); } void LoadPreferencesTreeView() { TreeStore store = new TreeStore(typeof(string), typeof(IPluginPreferences)); store.AppendValues(Catalog.GetString("General"), generalPreferences); store.AppendValues(Catalog.GetString("Undo"), undoPreferences); store.AppendValues(Catalog.GetString("Session"), sessionPreferences); TreeIter ti = store.AppendValues(Catalog.GetString("Plugins"), null); // Get all plugins from all managers that have preferences foreach(KeyValuePair kvp in PluginManager.AllManagers) foreach(Plugin p in kvp.Value.Plugins) if (p.PluginPreferences != null) store.AppendValues(ti, p.Name, p.PluginPreferences); PreferencesTreeView.Model = store; PreferencesTreeView.AppendColumn("", new CellRendererText (), "text", 0); PreferencesTreeView.HeadersVisible = false; PreferencesTreeView.Selection.Changed += OnPreferencesTreeViewSelectionChanged; PreferencesTreeView.Selection.SelectPath(new TreePath("0")); } void OnPreferencesTreeViewSelectionChanged (object o, EventArgs args) { TreeSelection sel = (TreeSelection)o; TreeModel tm; TreeIter ti; if (sel.GetSelected(out tm, out ti)) { IPluginPreferences ipp = (IPluginPreferences) tm.GetValue (ti, 1); // If user tried to select a header row, keep the previous selection if (ipp == null) { sel.SelectIter(selectedIter); return; } if (PreferencesPaned.Child2 != null) PreferencesPaned.Remove(PreferencesPaned.Child2); PreferencesPaned.Pack2(ipp.Widget, true, false); ipp.LoadPreferences(); ipp.Widget.ShowAll(); selectedIter = ti; } } void OnDialogResponse(object o, Gtk.ResponseArgs args) { // If the widget is not removed we can not show it again // at a later invocation of PreferencesDialog if (PreferencesPaned.Child2 != null) PreferencesPaned.Remove(PreferencesPaned.Child2); this.Destroy(); } } class GeneralPreferences : IPluginPreferences { [Gtk.Builder.Object] Gtk.VBox GeneralPreferencesVBox; [Gtk.Builder.Object] Entry LayoutFileEntry; [Gtk.Builder.Object] CheckButton UseCurrentLayoutCheckButton; [Gtk.Builder.Object] ComboBox DefaultEditModeComboBox; [Gtk.Builder.Object] Entry TempDirEntry; [Gtk.Builder.Object] Button SelectTempDirButton; [Gtk.Builder.Object] Button SelectLayoutButton; enum EditModeEnum { Insert, Overwrite } enum NumberBaseEnum { Hexadecimal, Decimal, Octal } Window mainWindow; Preferences prefs; public GeneralPreferences(Window mw) { mainWindow = mw; prefs = Preferences.Instance; } public Widget Widget { get { if (GeneralPreferencesVBox == null) InitWidget(); return GeneralPreferencesVBox; } } public void LoadPreferences() { if (GeneralPreferencesVBox == null) InitWidget(); string val; // // val = prefs["Default.Layout.File"]; LayoutFileEntry.Text = val; LoadCheckButtonPreference( "Default.Layout.UseCurrent", UseCurrentLayoutCheckButton, false); // // // val = prefs["Default.EditMode"]; if (val != "Insert" && val != "Overwrite") val = "Insert"; { EditModeEnum index; if (val == "Insert") index = EditModeEnum.Insert; else index = EditModeEnum.Overwrite; DefaultEditModeComboBox.Active = (int)index; } // // if (prefs["ByteBuffer.TempDir"] != System.IO.Path.GetTempPath()) TempDirEntry.Text = prefs["ByteBuffer.TempDir"]; else TempDirEntry.Text = ""; } public void SavePreferences() { // All preferences are applied instantly... // No need to save them here } void InitWidget() { Gtk.Builder builder = new Gtk.Builder(); builder.AddFromFile(FileResourcePath.GetDataPath("ui", "PreferencesDialog.ui")); builder.Autoconnect(this); SelectTempDirButton.Clicked += OnSelectTempDirButtonClicked; SelectLayoutButton.Clicked += OnSelectLayoutClicked; LayoutFileEntry.Changed += OnLayoutFileChanged; UseCurrentLayoutCheckButton.Toggled += OnUseCurrentLayoutToggled; DefaultEditModeComboBox.Changed += OnDefaultEditModeChanged; TempDirEntry.FocusOutEvent += OnTempDirFocusOutEvent; } void LoadCheckButtonPreference(string key, CheckButton cb, bool defaultValue) { string val = prefs[key]; try { bool b = Convert.ToBoolean(val); cb.Active = b; } catch (FormatException e) { System.Console.WriteLine(e.Message); cb.Active = defaultValue; } } void OnSelectLayoutClicked(object o, EventArgs args) { LayoutSelectionDialog lsd = new LayoutSelectionDialog(null); Gtk.ResponseType response = (Gtk.ResponseType)lsd.Run(); if (response == Gtk.ResponseType.Ok && lsd.SelectedLayout != null) { LayoutFileEntry.Text = lsd.SelectedLayout; } lsd.Destroy(); } private void OnSelectTempDirButtonClicked(object o, EventArgs args) { FileChooserDialog fcd = new FileChooserDialog(Catalog.GetString("Select Directory"), mainWindow, FileChooserAction.CreateFolder, Catalog.GetString("Cancel"), ResponseType.Cancel, Catalog.GetString("Select"), ResponseType.Accept); if ((ResponseType)fcd.Run() == ResponseType.Accept) TempDirEntry.Text = fcd.Filename; fcd.Destroy(); } private void OnLayoutFileChanged(object o, EventArgs args) { prefs["Default.Layout.File"] = LayoutFileEntry.Text; } private void OnUseCurrentLayoutToggled(object o, EventArgs args) { prefs["Default.Layout.UseCurrent"] = UseCurrentLayoutCheckButton.Active.ToString(); } private void OnDefaultEditModeChanged(object o, EventArgs args) { TreeIter iter; if (DefaultEditModeComboBox.GetActiveIter (out iter)) prefs["Default.EditMode"] = (string) DefaultEditModeComboBox.Model.GetValue (iter, 0); } private void OnTempDirFocusOutEvent(object o, Gtk.FocusOutEventArgs a) { prefs["ByteBuffer.TempDir"] = TempDirEntry.Text; } } class SessionPreferences : IPluginPreferences { Preferences prefs; [Gtk.Builder.Object] Gtk.VBox SessionPreferencesVBox; [Gtk.Builder.Object] CheckButton LoadPreviousSessionCheckButton; [Gtk.Builder.Object] CheckButton AskBeforeLoadingSessionCheckButton; [Gtk.Builder.Object] CheckButton RememberCursorPositionCheckButton; [Gtk.Builder.Object] CheckButton RememberWindowGeometryCheckButton; public SessionPreferences(Window mw) { prefs = Preferences.Instance; } public Widget Widget { get { if (SessionPreferencesVBox == null) InitWidget(); return SessionPreferencesVBox; } } public void LoadPreferences() { if (SessionPreferencesVBox == null) InitWidget(); LoadCheckButtonPreference( "Session.LoadPrevious", LoadPreviousSessionCheckButton, true); LoadCheckButtonPreference( "Session.AskBeforeLoading", AskBeforeLoadingSessionCheckButton, false); LoadCheckButtonPreference( "Session.RememberCursorPosition", RememberCursorPositionCheckButton, true); LoadCheckButtonPreference( "Session.RememberWindowGeometry", RememberWindowGeometryCheckButton, true); } public void SavePreferences() { // All preferences are applied instantly... // No need to save them here } void LoadCheckButtonPreference(string key, CheckButton cb, bool defaultValue) { string val = prefs[key]; try { bool b = Convert.ToBoolean(val); cb.Active = b; } catch (FormatException e) { System.Console.WriteLine(e.Message); cb.Active = defaultValue; } } void InitWidget() { Gtk.Builder builder = new Gtk.Builder(); builder.AddFromFile(FileResourcePath.GetDataPath("ui", "PreferencesDialog.ui")); builder.Autoconnect(this); LoadPreviousSessionCheckButton.Toggled += OnLoadPreviousSessionToggled; AskBeforeLoadingSessionCheckButton.Toggled += AskBeforeLoadingSessionToggled; RememberCursorPositionCheckButton.Toggled += RememberCursorPositionToggled; RememberWindowGeometryCheckButton.Toggled += RememberWindowGeometryToggled; } void OnLoadPreviousSessionToggled(object o, EventArgs args) { if (LoadPreviousSessionCheckButton.Active) { AskBeforeLoadingSessionCheckButton.Sensitive = true; RememberCursorPositionCheckButton.Sensitive = true; RememberWindowGeometryCheckButton.Sensitive = true; } else { AskBeforeLoadingSessionCheckButton.Sensitive = false; RememberCursorPositionCheckButton.Sensitive = false; RememberWindowGeometryCheckButton.Sensitive = false; } prefs["Session.LoadPrevious"] = LoadPreviousSessionCheckButton.Active.ToString(); } void AskBeforeLoadingSessionToggled(object o, EventArgs args) { prefs["Session.AskBeforeLoading"] = AskBeforeLoadingSessionCheckButton.Active.ToString(); } void RememberCursorPositionToggled(object o, EventArgs args) { prefs["Session.RememberCursorPosition"] = RememberCursorPositionCheckButton.Active.ToString(); } void RememberWindowGeometryToggled(object o, EventArgs args) { prefs["Session.RememberWindowGeometry"] = RememberWindowGeometryCheckButton.Active.ToString(); } } class UndoPreferences : IPluginPreferences { Preferences prefs; [Gtk.Builder.Object] Gtk.VBox UndoPreferencesVBox; [Gtk.Builder.Object] RadioButton UndoLimitedRadioButton; [Gtk.Builder.Object] RadioButton UndoUnlimitedRadioButton; [Gtk.Builder.Object] SpinButton UndoActionsSpinButton; [Gtk.Builder.Object] RadioButton KeepUndoAlwaysRadioButton; [Gtk.Builder.Object] RadioButton KeepUndoMemoryRadioButton; [Gtk.Builder.Object] RadioButton KeepUndoNeverRadioButton; public UndoPreferences(Window mw) { prefs = Preferences.Instance; } public Widget Widget { get { if (UndoPreferencesVBox == null) InitWidget(); return UndoPreferencesVBox; } } public void LoadPreferences() { string val; // val = prefs["Undo.Limited"]; try { bool limited = Convert.ToBoolean(val); UndoLimitedRadioButton.Active = limited; UndoUnlimitedRadioButton.Active = !limited; } catch (FormatException e) { System.Console.WriteLine(e.Message); UndoLimitedRadioButton.Active = true; } // val = prefs["Undo.Actions"]; try { int actions = Convert.ToInt32(val); UndoActionsSpinButton.Value = actions; } catch (FormatException e) { System.Console.WriteLine(e.Message); UndoActionsSpinButton.Value = 100; } // val = prefs["Undo.KeepAfterSave"]; KeepUndoAlwaysRadioButton.Active = false; KeepUndoMemoryRadioButton.Active = false; KeepUndoNeverRadioButton.Active = false; switch(val.ToLower()) { case "always": KeepUndoAlwaysRadioButton.Active = true; break; case "never": KeepUndoNeverRadioButton.Active = true; break; case "memory": default: KeepUndoMemoryRadioButton.Active = true; break; } } public void SavePreferences() { // All preferences are applied instantly... // No need to save them here } void LoadCheckButtonPreference(string key, CheckButton cb, bool defaultValue) { string val = prefs[key]; try { bool b = Convert.ToBoolean(val); cb.Active = b; } catch (FormatException e) { System.Console.WriteLine(e.Message); cb.Active = defaultValue; } } void InitWidget() { Gtk.Builder builder = new Gtk.Builder(); builder.AddFromFile(FileResourcePath.GetDataPath("ui", "PreferencesDialog.ui")); builder.Autoconnect(this); UndoLimitedRadioButton.Toggled += OnUndoLimitedToggled; UndoActionsSpinButton.ValueChanged += OnUndoActionsValueChanged; KeepUndoAlwaysRadioButton.Toggled += OnKeepUndoAlwaysToggled; KeepUndoMemoryRadioButton.Toggled += OnKeepUndoMemoryToggled; KeepUndoNeverRadioButton.Toggled += OnKeepUndoNeverToggled; } private void OnUndoLimitedToggled(object o, EventArgs args) { prefs["Undo.Limited"] = UndoLimitedRadioButton.Active.ToString(); } private void OnUndoActionsValueChanged(object o, EventArgs args) { prefs["Undo.Actions"] = UndoActionsSpinButton.ValueAsInt.ToString(); } private void OnKeepUndoAlwaysToggled(object o, EventArgs args) { if (KeepUndoAlwaysRadioButton.Active) prefs["Undo.KeepAfterSave"] = "Always"; } private void OnKeepUndoMemoryToggled(object o, EventArgs args) { if (KeepUndoMemoryRadioButton.Active) prefs["Undo.KeepAfterSave"] = "Memory"; } private void OnKeepUndoNeverToggled(object o, EventArgs args) { if (KeepUndoNeverRadioButton.Active) prefs["Undo.KeepAfterSave"] = "Never"; } } } // end namespace bless-0.6.3/src/gui/dialogs/ProgressDialog.cs000066400000000000000000000053041374060072200211030ustar00rootroot00000000000000// created on 3/20/2005 at 2:47 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using Gtk; using Bless.Tools.Find; using Bless.Util; namespace Bless.Gui.Dialogs { /// /// A customizable progress dialog /// public class ProgressDialog : Gtk.Window { [Gtk.Builder.Object] Gtk.VBox ProgressVBox; [Gtk.Builder.Object] Gtk.ProgressBar ProgressBar; [Gtk.Builder.Object] Gtk.Label MessageLabel; [Gtk.Builder.Object] Gtk.Label DetailsLabel; bool cancelClicked; public ProgressDialog(string primary, Gtk.Window main) : base(primary) { Gtk.Builder builder = new Gtk.Builder(); builder.AddFromFile(FileResourcePath.GetDataPath("ui", "ProgressDialog.ui")); builder.Autoconnect(this); // setup window this.SkipTaskbarHint = false; this.TypeHint = Gdk.WindowTypeHint.Dialog; this.TransientFor = main; this.BorderWidth = 6; MessageLabel.Markup = "" + primary + ""; this.Add(ProgressVBox); this.Hide(); } public bool Update(object o, ProgressAction action) { if (action == ProgressAction.Hide) { this.Visible = false; return false; } else if (action == ProgressAction.Show) { this.Visible = true; return false; } else if (action == ProgressAction.Message) { this.Title = (string)o; MessageLabel.Markup = "" + (string)o + ""; return false; } else if (action == ProgressAction.Details) { DetailsLabel.Text = (string)o; return false; } else if (action == ProgressAction.Destroy) { this.Destroy(); return false; } ProgressBar.Fraction = (double)o; if (cancelClicked == true) { cancelClicked = false; return true; } else return false; } public void OnCancelButtonClicked(object o, EventArgs args) { cancelClicked = true; } protected override bool OnDeleteEvent(Gdk.Event e) { cancelClicked = true; return true; } } }// end namespace bless-0.6.3/src/gui/dialogs/RevertConfirmationAlert.cs000066400000000000000000000030351374060072200227660ustar00rootroot00000000000000// created on 2/8/2005 at 2:52 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using Gtk; using Mono.Unix; namespace Bless.Gui.Dialogs { ///An alert dialog box as recommended in the Gnome HIG public class RevertConfirmationAlert : Alert { public RevertConfirmationAlert(string primary, Gtk.Window parent) : base(string.Format(Catalog.GetString("Revert file '{0}' to its last saved state?"), primary), Catalog.GetString("If you revert, all changes made since the last save will be lost."), parent) { image.SetFromStock(Gtk.Stock.DialogWarning, Gtk.IconSize.Dialog); this.AddButton(Gtk.Stock.Cancel, ResponseType.Cancel); this.AddButton(Gtk.Stock.RevertToSaved, ResponseType.Ok); this.ShowAll(); } } } // namespace bless-0.6.3/src/gui/dialogs/SaveConfirmationAlert.cs000066400000000000000000000032061374060072200224150ustar00rootroot00000000000000// created on 10/26/2004 at 7:01 PM /* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using Gtk; using Mono.Unix; namespace Bless.Gui.Dialogs { ///An alert dialog box as recommended in the Gnome HIG public class SaveConfirmationAlert : Alert { public SaveConfirmationAlert(string primary, Gtk.Window parent) : base(string.Format(Catalog.GetString("Save changes to file '{0}' before closing?"), primary), Catalog.GetString("If you don't save, all changes made since the last save will be lost."), parent) { image.SetFromStock(Gtk.Stock.DialogWarning, Gtk.IconSize.Dialog); this.AddButton(Catalog.GetString("Close without Saving"), ResponseType.No); this.AddButton(Gtk.Stock.Cancel, ResponseType.Cancel); this.AddButton(Gtk.Stock.Save, ResponseType.Ok); this.DefaultResponse = ResponseType.Cancel; this.ShowAll(); } } }bless-0.6.3/src/gui/dialogs/SaveConfirmationMultiAlert.cs000066400000000000000000000062701374060072200234340ustar00rootroot00000000000000// created on 12/25/2004 at 6:33 PM /* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using Gtk; using Mono.Unix; namespace Bless.Gui.Dialogs { public class SaveFileItem { public bool Save; public string Name; public int Page; public SaveFileItem(bool s, string n, int p) {Save = s; Name = n; Page = p;} } ///An alert dialog box as recommended in the Gnome HIG public class SaveConfirmationMultiAlert : Alert { TreeView treeView; SaveFileItem[] fileList; public SaveConfirmationMultiAlert(SaveFileItem[] list, Gtk.Window parent) : base(string.Format( Catalog.GetPluralString("There is {0} file with unsaved changes.", "There are {0} files with unsaved changes.", list.Length) + " " + Catalog.GetString("Save changes before closing?"), list.Length), Catalog.GetString("If you don't save, all changes made since the last save will be lost."), parent) { fileList = list; image.SetFromStock(Gtk.Stock.DialogWarning, Gtk.IconSize.Dialog); Label label = new Label(Catalog.GetString("\nSelect the files you want to save:\n")); label.Xalign = 0.0f; VBox vb = new VBox(); vb.PackStart(label); treeView = CreateView(list); vb.PackStart(treeView); labelBox.PackStart(vb); labelBox.ReorderChild(vb, 1); this.AddButton(Catalog.GetString("Close without Saving"), ResponseType.No); this.AddButton(Gtk.Stock.Cancel, ResponseType.Cancel); this.AddButton(Gtk.Stock.Save, ResponseType.Ok); this.DefaultResponse = ResponseType.Cancel; this.ShowAll(); } private TreeView CreateView(SaveFileItem[] list) { ListStore store = new ListStore (typeof (bool), typeof (string)); TreeView tv = new TreeView(); tv.Model = store; tv.HeadersVisible = false; CellRendererToggle crt = new CellRendererToggle(); crt.Activatable = true; crt.Toggled += OnItemToggled; tv.AppendColumn ("Save", crt, "active", 0); tv.AppendColumn ("Name", new CellRendererText(), "text", 1); foreach (SaveFileItem item in list) { item.Save = true; store.AppendValues(item.Save, item.Name); } return tv; } private void OnItemToggled (object o, ToggledArgs args) { ListStore store = (ListStore)treeView.Model; Gtk.TreeIter iter; if (store.GetIterFromString (out iter, args.Path)) { bool val = (bool) store.GetValue (iter, 0); store.SetValue (iter, 0, !val); int row = Convert.ToInt32(args.Path); fileList[row].Save = !fileList[row].Save; } } } } bless-0.6.3/src/gui/dialogs/WarningAlert.cs000066400000000000000000000025341374060072200205560ustar00rootroot00000000000000// created on 4/29/2005 at 2:52 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using Gtk; namespace Bless.Gui.Dialogs { ///An alert dialog box as recommended in the Gnome HIG public class WarningAlert : Alert { public WarningAlert(string primary, string secondary, Gtk.Window parent) : base(primary, secondary, parent) { image.SetFromStock(Gtk.Stock.DialogWarning, Gtk.IconSize.Dialog); this.AddButton(Gtk.Stock.Cancel, ResponseType.Cancel); this.AddButton(Gtk.Stock.Ok, ResponseType.Ok); this.ShowAll(); } } } // namespace bless-0.6.3/src/gui/drawers/000077500000000000000000000000001374060072200156535ustar00rootroot00000000000000bless-0.6.3/src/gui/drawers/AsciiDrawer.cs000066400000000000000000000041661374060072200204060ustar00rootroot00000000000000// created on 6/28/2004 at 4:46 PM /* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ namespace Bless.Gui.Drawers { ///Draws the ascii representation of a byte public class AsciiDrawer : Drawer { // Use the Zero Width Non-Joiner character \u200c to avoid ligatures static readonly string AsciiTable = "................................ !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHI\u200cJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghi\u200cjklmnopqrs\u200ctuvwxyz{|}~................................................................................................................................."; public AsciiDrawer(Gtk.Widget wid, Information inf) : base(wid, inf) { } protected override void Draw(Gdk.GC gc, Gdk.Drawable dest, int x, int y, byte b, Gdk.Pixmap pix) { dest.DrawDrawable(gc, pix, b*width, 0, x, y, width, height); } protected override Gdk.Pixmap Create(Gdk.Color fg, Gdk.Color bg) { Gdk.Window win = widget.GdkWindow; Gdk.GC gc = new Gdk.GC(win); Gdk.Pixmap pix = new Gdk.Pixmap(win, 256*width, height, -1); // draw the background gc.RgbFgColor = bg; pix.DrawRectangle(gc, true, 0, 0, 256*width, height); // render the bytes string s = AsciiDrawer.AsciiTable; //System.Console.WriteLine(s); pangoLayout.SetText(s); gc.RgbFgColor = fg; pix.DrawLayout(gc, 0, 0, pangoLayout); return pix; } } } //namespace bless-0.6.3/src/gui/drawers/BinaryDrawer.cs000066400000000000000000000036041374060072200205760ustar00rootroot00000000000000// created on 6/28/2004 at 4:48 PM /* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ namespace Bless.Gui.Drawers { ///Draws the binary representation of a byte public class BinaryDrawer : Drawer { public BinaryDrawer(Gtk.Widget wid, Information inf) : base(wid, inf) { } protected override void Draw(Gdk.GC gc, Gdk.Drawable dest, int x, int y, byte b, Gdk.Pixmap pix) { // draw from the end backwards x += 6 * width; for (int i = 0; i < 4; i++) { byte k = (byte)(b & 3); dest.DrawDrawable(gc, pix, k*2*width, 0, x, y, 2*width, height); x -= 2 * width; b = (byte)(b >> 2); } } protected override Gdk.Pixmap Create(Gdk.Color fg, Gdk.Color bg) { Gdk.Window win = widget.GdkWindow; Gdk.GC gc = new Gdk.GC(win); Gdk.Pixmap pix = new Gdk.Pixmap(win, 4*2*width, height, -1); // draw the background gc.RgbFgColor = bg; pix.DrawRectangle(gc, true, 0, 0, 4*2*width, height); // render the bytes string s = "00011011"; //Console.WriteLine(s); pangoLayout.SetText(s); gc.RgbFgColor = fg; pix.DrawLayout(gc, 0, 0, pangoLayout); return pix; } } } //namespacebless-0.6.3/src/gui/drawers/DecimalDrawer.cs000066400000000000000000000050571374060072200207140ustar00rootroot00000000000000// created on 7/1/2004 at 8:10 PM /* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ namespace Bless.Gui.Drawers { ///Draws the decimal representation of a byte public class DecimalDrawer : Drawer { static readonly string DecimalTable = "000001002003004005006007008009010011012013014015016017018019020021022023024025026027028029030031032033034035036037038039040041042043044045046047048049050051052053054055056057058059060061062063064065066067068069070071072073074075076077078079080081082083084085086087088089090091092093094095096097098099100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255"; public DecimalDrawer(Gtk.Widget wid, Information inf) : base(wid, inf) { } protected override void Draw(Gdk.GC gc, Gdk.Drawable dest, int x, int y, byte b, Gdk.Pixmap pix) { dest.DrawDrawable(gc, pix, b*3*width, 0, x, y, 3*width, height); } protected override Gdk.Pixmap Create(Gdk.Color fg, Gdk.Color bg) { Gdk.Window win = widget.GdkWindow; Gdk.GC gc = new Gdk.GC(win); Gdk.Pixmap pix = new Gdk.Pixmap(win, 256*3*width, height, -1); // draw the background gc.RgbFgColor = bg; pix.DrawRectangle(gc, true, 0, 0, 256*3*width, height); // render the bytes string s = DecimalDrawer.DecimalTable; //System.Console.WriteLine(s); pangoLayout.SetText(s); gc.RgbFgColor = fg; pix.DrawLayout(gc, 0, 0, pangoLayout); return pix; } } } //namespacebless-0.6.3/src/gui/drawers/Drawer.cs000066400000000000000000000314411374060072200174310ustar00rootroot00000000000000// created on 6/14/2004 at 10:55 PM /* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.Collections.Specialized; using Gtk; using Gdk; using Pango; namespace Bless.Gui.Drawers { ///Fast font drawing class public abstract class Drawer { public class Color { public Color(Gdk.Color color) { this.GdkColor = color; } public Gdk.Color GdkColor; } public class Information { public string FontName; public string FontLanguage; public Drawer.Color[,] fgNormal; public Drawer.Color[,] bgNormal; public Drawer.Color[,] fgHighlight; public Drawer.Color[,] bgHighlight; public bool Uppercase; public Information() { FontName = "BlessCourier, Courier 12"; FontLanguage = "utf-8"; fgNormal = new Drawer.Color[2, 2]; bgNormal = new Drawer.Color[2, 2]; fgHighlight = new Drawer.Color[2, (int)HighlightType.Sentinel]; bgHighlight = new Drawer.Color[2, (int)HighlightType.Sentinel]; for (int i = 0; i < 2; i++) { fgNormal[0, i] = new Drawer.Color(Gdk.Color.Zero); fgNormal[1, i] = new Drawer.Color(Gdk.Color.Zero); bgNormal[0, i] = new Drawer.Color(Gdk.Color.Zero); bgNormal[1, i] = new Drawer.Color(Gdk.Color.Zero); } // initialize default colors Gdk.Color.Parse("black", ref fgNormal[(int)RowType.Even, (int)ColumnType.Even].GdkColor); Gdk.Color.Parse("white", ref bgNormal[(int)RowType.Even, (int)ColumnType.Even].GdkColor); Gdk.Color.Parse("blue", ref fgNormal[(int)RowType.Even, (int)ColumnType.Odd].GdkColor); Gdk.Color.Parse("white", ref bgNormal[(int)RowType.Even, (int)ColumnType.Odd].GdkColor); Gdk.Color.Parse("black", ref fgNormal[(int)RowType.Odd, (int)ColumnType.Even].GdkColor); Gdk.Color.Parse("white", ref bgNormal[(int)RowType.Odd, (int)ColumnType.Even].GdkColor); Gdk.Color.Parse("blue", ref fgNormal[(int)RowType.Odd, (int)ColumnType.Odd].GdkColor); Gdk.Color.Parse("white", ref bgNormal[(int)RowType.Odd, (int)ColumnType.Odd].GdkColor); // leave unspecified... // if not specified by user they will // be set up using theme defaults for (int i = 0; i < (int)HighlightType.Sentinel; i++) { fgHighlight[(int)RowType.Even, i] = null; bgHighlight[(int)RowType.Even, i] = null; fgHighlight[(int)RowType.Odd, i] = null; bgHighlight[(int)RowType.Odd, i] = null; } Uppercase = false; } // setup unspecified hightlight colors using theme default colors public void SetupHighlight(Gtk.Widget widget) { Gdk.Color selFg; Gdk.Color selBg; Gdk.Color patMatchFg; Gdk.Color patMatchBg; selFg = widget.Style.TextColors[(int)StateType.Selected]; selBg = widget.Style.BaseColors[(int)StateType.Selected]; patMatchBg = MakeColorLighter(selBg, 0.6); patMatchFg = MakeColorDarker(selFg, 0.4); // Selection if (fgHighlight[(int)RowType.Even, (int)HighlightType.Selection] == null) fgHighlight[(int)RowType.Even, (int)HighlightType.Selection] = new Drawer.Color(selFg); if (bgHighlight[(int)RowType.Even, (int)HighlightType.Selection] == null) bgHighlight[(int)RowType.Even, (int)HighlightType.Selection] = new Drawer.Color(selBg); if (fgHighlight[(int)RowType.Odd, (int)HighlightType.Selection] == null) fgHighlight[(int)RowType.Odd, (int)HighlightType.Selection] = new Drawer.Color(selFg); if (bgHighlight[(int)RowType.Odd, (int)HighlightType.Selection] == null) bgHighlight[(int)RowType.Odd, (int)HighlightType.Selection] = new Drawer.Color(selBg); // Secondary selection if (fgHighlight[(int)RowType.Even, (int)HighlightType.PatternMatch] == null) fgHighlight[(int)RowType.Even, (int)HighlightType.PatternMatch] = new Drawer.Color(patMatchFg); if (bgHighlight[(int)RowType.Even, (int)HighlightType.PatternMatch] == null) bgHighlight[(int)RowType.Even, (int)HighlightType.PatternMatch] = new Drawer.Color(patMatchBg); if (fgHighlight[(int)RowType.Odd, (int)HighlightType.PatternMatch] == null) fgHighlight[(int)RowType.Odd, (int)HighlightType.PatternMatch] = new Drawer.Color(patMatchFg); if (bgHighlight[(int)RowType.Odd, (int)HighlightType.PatternMatch] == null) bgHighlight[(int)RowType.Odd, (int)HighlightType.PatternMatch] = new Drawer.Color(patMatchBg); } // Make a color lighter while keeping its hue Gdk.Color MakeColorLighter(Gdk.Color col, double factor) { Gdk.Color light = new Gdk.Color(); light.Red = (ushort)(col.Red + (ushort.MaxValue - col.Red) * factor); light.Blue = (ushort)(col.Blue + (ushort.MaxValue - col.Blue) * factor); light.Green = (ushort)(col.Green + (ushort.MaxValue - col.Green) * factor); return light; } // Make a color darker while keeping its hue Gdk.Color MakeColorDarker(Gdk.Color col, double factor) { Gdk.Color dark = new Gdk.Color(); dark.Red = (ushort)(col.Red * factor); dark.Blue = (ushort)(col.Blue * factor); dark.Green = (ushort)(col.Green * factor); return dark; } } // the order of this enumeration denotes the drawing priority of each highlight type // For example if a Bookmark and PatternMatch highlight are to be drawn on the same offset // the PatternMatch type will be drawn. In the same manner the Selection highlight // is always drawn, whereas the Normal highlight is always drawn over. public enum HighlightType { Normal, Bookmark, PatternMatch, Selection, Sentinel } public enum RowType { Even, Odd } public enum ColumnType { Even, Odd } // the widget the font will finally // be printed on (used for info only) protected Gtk.Widget widget; protected Pango.FontDescription fontDescription; protected Information info; protected Gdk.Pixmap[,] pixmapsNormal; protected Gdk.Pixmap[,] pixmapsHighlight; protected StringCollection pixmapIds; // pango layout used for rendering text protected Pango.Layout pangoLayout; protected Gdk.GC[,] backGC; protected int width; protected int height; ///Constructor public Drawer(Gtk.Widget wid, Information inf) { widget = wid; info = inf; pixmapIds = new StringCollection(); // make sure highlight colors are set info.SetupHighlight(wid); fontDescription = Pango.FontDescription.FromString(info.FontName); Pango.Language lang = Pango.Language.FromString(info.FontLanguage); Pango.Context pangoCtx = widget.PangoContext; pangoCtx.FontDescription = fontDescription; pangoCtx.Language = lang; // set the font height and width pangoLayout = new Pango.Layout(pangoCtx); // we use a monospaced font, the actual character doesn't matter pangoLayout.SetText("X"); pangoLayout.GetPixelSize(out width, out height); pangoLayout.SetText(""); // create the font pixmaps InitializePixmaps(); InitializeBackgroundGCs(); } void InitializePixmaps() { pixmapsNormal = new Gdk.Pixmap[2,2]; pixmapsHighlight = new Gdk.Pixmap[2,(int)HighlightType.Sentinel]; Drawer.Color colorFg; Drawer.Color colorBg; //even rows colorFg = info.fgNormal[(int)RowType.Even, (int)ColumnType.Even]; colorBg = info.bgNormal[(int)RowType.Even, (int)ColumnType.Even]; pixmapsNormal[(int)RowType.Even, (int)ColumnType.Even] = CreateWrapper(colorFg, colorBg); colorFg = info.fgNormal[(int)RowType.Even, (int)ColumnType.Odd]; colorBg = info.bgNormal[(int)RowType.Even, (int)ColumnType.Odd]; pixmapsNormal[(int)RowType.Even, (int)ColumnType.Odd] = CreateWrapper(colorFg, colorBg); colorFg = info.fgHighlight[(int)RowType.Even, (int)HighlightType.Selection]; colorBg = info.bgHighlight[(int)RowType.Even, (int)HighlightType.Selection]; pixmapsHighlight[(int)RowType.Even, (int)HighlightType.Selection] = CreateWrapper(colorFg, colorBg); colorFg = info.fgHighlight[(int)RowType.Even, (int)HighlightType.PatternMatch]; colorBg = info.bgHighlight[(int)RowType.Even, (int)HighlightType.PatternMatch]; pixmapsHighlight[(int)RowType.Even, (int)HighlightType.PatternMatch] = CreateWrapper(colorFg, colorBg); //odd rows colorFg = info.fgNormal[(int)RowType.Odd, (int)ColumnType.Even]; colorBg = info.bgNormal[(int)RowType.Odd, (int)ColumnType.Even]; pixmapsNormal[(int)RowType.Odd, (int)ColumnType.Even] = CreateWrapper(colorFg, colorBg); colorFg = info.fgNormal[(int)RowType.Odd, (int)ColumnType.Odd]; colorBg = info.bgNormal[(int)RowType.Odd, (int)ColumnType.Odd]; pixmapsNormal[(int)RowType.Odd, (int)ColumnType.Odd] = CreateWrapper(colorFg, colorBg); colorFg = info.fgHighlight[(int)RowType.Odd, (int)HighlightType.Selection]; colorBg = info.bgHighlight[(int)RowType.Odd, (int)HighlightType.Selection]; pixmapsHighlight[(int)RowType.Odd, (int)HighlightType.Selection] = CreateWrapper(colorFg, colorBg); colorFg = info.fgHighlight[(int)RowType.Odd, (int)HighlightType.PatternMatch]; colorBg = info.bgHighlight[(int)RowType.Odd, (int)HighlightType.PatternMatch]; pixmapsHighlight[(int)RowType.Odd, (int)HighlightType.PatternMatch] = CreateWrapper(colorFg, colorBg); } void InitializeBackgroundGCs() { // initialize background GCs backGC = new Gdk.GC[2, (int)Drawer.HighlightType.Sentinel]; for (int i = 0; i < 2; i++) for (int j = 0; j < (int)Drawer.HighlightType.Sentinel; j++) backGC[i,j] = new Gdk.GC(widget.GdkWindow); Drawer.Color col; // normal col = info.bgNormal[(int)RowType.Even, (int)ColumnType.Even]; backGC[(int)RowType.Even, (int)HighlightType.Normal].RgbFgColor = col.GdkColor; col = info.bgNormal[(int)RowType.Odd, (int)ColumnType.Even]; backGC[(int)RowType.Odd, (int)HighlightType.Normal].RgbFgColor = col.GdkColor; // selection col = info.bgHighlight[(int)RowType.Even, (int)HighlightType.Selection]; backGC[(int)RowType.Even, (int)HighlightType.Selection].RgbFgColor = col.GdkColor; col = info.bgHighlight[(int)RowType.Odd, (int)HighlightType.Selection]; backGC[(int)RowType.Odd, (int)HighlightType.Selection].RgbFgColor = col.GdkColor; // secondary selection col = info.bgHighlight[(int)RowType.Even, (int)HighlightType.PatternMatch]; backGC[(int)RowType.Even, (int)HighlightType.PatternMatch].RgbFgColor = col.GdkColor; col = info.bgHighlight[(int)RowType.Odd, (int)HighlightType.PatternMatch]; backGC[(int)RowType.Odd, (int)HighlightType.PatternMatch].RgbFgColor = col.GdkColor; } /// /// Wrapper around create to avoid creating pixmaps we already have /// private Gdk.Pixmap CreateWrapper(Drawer.Color fg, Drawer.Color bg) { string id = PixmapManager.Instance.GetPixmapId(this.GetType(), info, fg.GdkColor, bg.GdkColor); Gdk.Pixmap pix = PixmapManager.Instance.GetPixmap(id); if (pix == null) { pix = Create(fg.GdkColor, bg.GdkColor); // can be null for DummyDrawer if (pix != null) { PixmapManager.Instance.AddPixmap(id, pix); PixmapManager.Instance.ReferencePixmap(id); pixmapIds.Add(id); } } else { PixmapManager.Instance.ReferencePixmap(id); pixmapIds.Add(id); } return pix; } ///Creates a pixmap with the drawn data abstract protected Gdk.Pixmap Create(Gdk.Color fg, Gdk.Color bg); ///Draws the a byte abstract protected void Draw(Gdk.GC gc, Gdk.Drawable dest, int x, int y, byte b, Gdk.Pixmap pix); public void DrawNormal(Gdk.GC gc, Gdk.Drawable dest, int x, int y, byte b, RowType rowType, ColumnType colType) { Draw(gc, dest, x, y, b, pixmapsNormal[(int)rowType, (int)colType]); } public void DrawHighlight(Gdk.GC gc, Gdk.Drawable dest, int x, int y, byte b, RowType rowType, HighlightType ht) { Draw(gc, dest, x, y, b, pixmapsHighlight[(int)rowType, (int)ht]); } public Gdk.GC GetBackgroundGC(RowType rowType, HighlightType ht) { return backGC[(int)rowType, (int)ht]; } public void DisposePixmaps() { foreach(string id in pixmapIds) PixmapManager.Instance.DereferencePixmap(id); pixmapIds.Clear(); } public int Width{ get { return width; } } public int Height{ get { return height; } } public Drawer.Information Info{ get { return info; } } } ///dummy public class DummyDrawer : Drawer { public DummyDrawer(Gtk.Widget wid, Information inf) : base(wid, inf) { } protected override void Draw(Gdk.GC gc, Gdk.Drawable dest, int x, int y, byte b, Gdk.Pixmap pix) { } protected override Gdk.Pixmap Create(Gdk.Color fg, Gdk.Color bg) { return null; } } } // end namespace bless-0.6.3/src/gui/drawers/HexDrawer.cs000066400000000000000000000067011374060072200200770ustar00rootroot00000000000000// created on 6/28/2004 at 4:18 PM /* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ namespace Bless.Gui.Drawers { ///Draws the hex representation of a byte public class HexDrawer : Drawer { // Use the Zero Width Non-Joiner character \u200c to avoid ligatures static readonly string HexTableLower = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeef\u200Cf0f1f2f3f4f5f6f7f8f9fafbfcfdfef\u200cf"; static readonly string HexTableUpper = "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF"; public HexDrawer(Gtk.Widget wid, Information inf) : base(wid, inf) { } protected override void Draw(Gdk.GC gc, Gdk.Drawable dest, int x, int y, byte b, Gdk.Pixmap pix) { dest.DrawDrawable(gc, pix, b*2*width, 0, x, y, 2*width, height); } protected override Gdk.Pixmap Create(Gdk.Color fg, Gdk.Color bg) { Gdk.Window win = widget.GdkWindow; Gdk.GC gc = new Gdk.GC(win); Gdk.Pixmap pix = new Gdk.Pixmap(win, 256*2*width, height, -1); // draw the background gc.RgbFgColor = bg; pix.DrawRectangle(gc, true, 0, 0, 256*2*width, height); // render the bytes string s; if (info.Uppercase == false) s = HexDrawer.HexTableLower; else s = HexDrawer.HexTableUpper; //System.Console.WriteLine(s); gc.RgbFgColor = fg; // Render the text in two parts (256 printable characters each). We do // this to work around a bug in some drivers that fail to render text // that ends up wider than 4096 pixels. pangoLayout.SetText(s.Substring(0,256)); pix.DrawLayout(gc, 0, 0, pangoLayout); // The second part also contains the two Zero Width Non-Joiner // characters, so it's actually 258 string characters, although still // 256 printable characters. pangoLayout.SetText(s.Substring(256)); pix.DrawLayout(gc, 128*2*width, 0, pangoLayout); return pix; } } } //namespace bless-0.6.3/src/gui/drawers/OctalDrawer.cs000066400000000000000000000050401374060072200204100ustar00rootroot00000000000000// created on 7/1/2004 at 8:41 PM /* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ namespace Bless.Gui.Drawers { ///Draws the octal representation of a byte public class OctalDrawer : Drawer { static readonly string OctalTable = "000001002003004005006007010011012013014015016017020021022023024025026027030031032033034035036037040041042043044045046047050051052053054055056057060061062063064065066067070071072073074075076077100101102103104105106107110111112113114115116117120121122123124125126127130131132133134135136137140141142143144145146147150151152153154155156157160161162163164165166167170171172173174175176177200201202203204205206207210211212213214215216217220221222223224225226227230231232233234235236237240241242243244245246247250251252253254255256257260261262263264265266267270271272273274275276277300301302303304305306307310311312313314315316317320321322323324325326327330331332333334335336337340341342343344345346347350351352353354355356357360361362363364365366367370371372373374375376377"; public OctalDrawer(Gtk.Widget wid, Information inf) : base(wid, inf) { } protected override void Draw(Gdk.GC gc, Gdk.Drawable dest, int x, int y, byte b, Gdk.Pixmap pix) { dest.DrawDrawable(gc, pix, b*3*width, 0, x, y, 3*width, height); } protected override Gdk.Pixmap Create(Gdk.Color fg, Gdk.Color bg) { Gdk.Window win = widget.GdkWindow; Gdk.GC gc = new Gdk.GC(win); Gdk.Pixmap pix = new Gdk.Pixmap(win, 256*3*width, height, -1); // draw the background gc.RgbFgColor = bg; pix.DrawRectangle(gc, true, 0, 0, 256*3*width, height); // render the bytes string s = OctalDrawer.OctalTable; //System.Console.WriteLine(s); pangoLayout.SetText(s); gc.RgbFgColor = fg; pix.DrawLayout(gc, 0, 0, pangoLayout); return pix; } } } //namespacebless-0.6.3/src/gui/drawers/PixmapManager.cs000066400000000000000000000051011374060072200207300ustar00rootroot00000000000000// created on 12/23/2006 at 3:50 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System.Collections.Generic; using Gdk; namespace Bless.Gui.Drawers { /// /// Handles drawer pixmaps in an memory efficient manner /// class PixmapManager { static private PixmapManager manager; static public PixmapManager Instance { get { if (manager == null) manager = new PixmapManager(); return manager; } } Dictionary pixmaps; Dictionary references; private PixmapManager() { pixmaps = new Dictionary(); references = new Dictionary(); } /// /// Get the id of the pixmap with the specified properties /// public string GetPixmapId(System.Type type, Drawer.Information info, Gdk.Color fg, Gdk.Color bg) { return string.Format("{0}{1}{2}{3}{4}{5}", type, info.FontName, info.FontLanguage, info.Uppercase, fg.ToString(), bg.ToString()); } /// /// Get the pixmap with the specified id. /// Returns null if the pixmap doesn't exist /// public Gdk.Pixmap GetPixmap(string id) { Gdk.Pixmap pix = null; if (pixmaps.ContainsKey(id)) pix = pixmaps[id]; return pix; } /// /// Add the pixmap to the collection /// public void AddPixmap(string id, Gdk.Pixmap pix) { pixmaps[id] = pix; references[id] = 0; } /// /// Mark that we are using the pixmap /// public void ReferencePixmap(string id) { ++references[id]; } /// /// Mark that we aren't using the pixmap anymore. /// If nobody uses it, dispose of it /// public void DereferencePixmap(string id) { --references[id]; if (references[id] <= 0) { pixmaps[id].Dispose(); pixmaps.Remove(id); references.Remove(id); } } } }bless-0.6.3/src/gui/plugins/000077500000000000000000000000001374060072200156655ustar00rootroot00000000000000bless-0.6.3/src/gui/plugins/BitwiseOperationsPlugin.cs000066400000000000000000000402131374060072200230450ustar00rootroot00000000000000// created on 4/3/2007 at 6:30 PM /* * Copyright (c) 2007, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.Text; using System.Threading; using Gtk; using Bless.Util; using Bless.Gui.Dialogs; using Bless.Gui; using Bless.Plugins; using Bless.Buffers; using Mono.Unix; namespace Bless.Gui.Plugins { /// /// A plugin to perform bytewise operation on data /// public class BitwiseOperationsPlugin : GuiPlugin { BitwiseOperationsWidget widget; DataBook dataBook; Gtk.Action performAction; const string uiXml = "" + " " + " " + " " + "" + "" + " " + " " + " " + ""; Window mainWindow; UIManager uiManager; public BitwiseOperationsPlugin(Window mw, UIManager uim) { mainWindow = mw; uiManager = uim; dataBook = (DataBook)GetDataBook(mw); name = "BitwiseOperations"; author = "Alexandros Frantzis"; description = "Bitwise operations on data"; loadAfter.Add("EditOperations"); } public override bool Load() { AddMenuItems(uiManager); widget = new BitwiseOperationsWidget((DataBook)GetDataBook(mainWindow), performAction); widget.Visible = false; WidgetGroup wgroup = (WidgetGroup)GetWidgetGroup(mainWindow, 0); wgroup.Add(widget); dataBook.PageAdded += new DataView.DataViewEventHandler(OnDataViewAdded); dataBook.Removed += new RemovedHandler(OnDataViewRemoved); dataBook.SwitchPage += new SwitchPageHandler(OnSwitchPage); loaded = true; return true; } private void AddMenuItems(UIManager uim) { ActionEntry[] actionEntries = new ActionEntry[] { new ActionEntry ("BitwiseOperationsAction", Stock.Execute, Catalog.GetString("_Bitwise Operations"), "B", null, new EventHandler(OnBitwiseOperationsActivated)), new ActionEntry ("PerformBitwiseOperationAction", Stock.Execute, Catalog.GetString("Perform Operation"), "B", null, new EventHandler(OnPerformBitwiseOperation)), }; ActionGroup group = new ActionGroup ("BitwiseOperationsActions"); group.Add (actionEntries); uim.InsertActionGroup(group, 0); uim.AddUiFromString(uiXml); performAction = (Gtk.Action)uim.GetAction("/DefaultAreaPopup/ExtraAreaPopupItems/PerformBitwiseOperation"); uim.EnsureUpdate(); } void OnDataViewAdded(DataView dv) { dv.Buffer.Changed += new ByteBuffer.ChangedHandler(OnBufferContentsChanged); dv.BufferChanged += new DataView.DataViewEventHandler(OnBufferChanged); dv.CursorChanged += new DataView.DataViewEventHandler(OnCursorChanged); dv.SelectionChanged += new DataView.DataViewEventHandler(OnSelectionChanged); } void OnDataViewRemoved(object o, RemovedArgs args) { DataView dv = ((DataViewDisplay)args.Widget).View; dv.Buffer.Changed -= new ByteBuffer.ChangedHandler(OnBufferContentsChanged); dv.BufferChanged -= new DataView.DataViewEventHandler(OnBufferChanged); dv.CursorChanged -= new DataView.DataViewEventHandler(OnCursorChanged); dv.SelectionChanged -= new DataView.DataViewEventHandler(OnSelectionChanged); } void OnBufferChanged(DataView dv) { UpdateBitwiseOperationsWidget(dv); } void OnBufferContentsChanged(ByteBuffer bb) { Gtk.Application.Invoke(delegate { DataView dv = null; // find DataView that owns bb foreach (DataViewDisplay dvtemp in dataBook.Children) { if (dvtemp.View.Buffer == bb) { dv = dvtemp.View; break; } } UpdateBitwiseOperationsWidget(dv); }); } void OnSwitchPage(object o, SwitchPageArgs args) { DataView dv = ((DataViewDisplay)dataBook.GetNthPage((int)args.PageNum)).View; UpdateBitwiseOperationsWidget(dv); } void OnCursorChanged(DataView dv) { UpdateBitwiseOperationsWidget(dv); } void OnSelectionChanged(DataView dv) { UpdateBitwiseOperationsWidget(dv); } void UpdateBitwiseOperationsWidget(DataView dv) { if (dataBook.NPages == 0) return; DataView curdv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; if (curdv != dv) return; widget.Update(dv); } ///Handle the Tools -> Bitwise Operations command public void OnBitwiseOperationsActivated(object o, EventArgs args) { widget.Show(); } public void OnPerformBitwiseOperation(object o, EventArgs args) { widget.PerformOperation(); } } /// /// A widget for bitwise operations /// public class BitwiseOperationsWidget : Gtk.HBox { [Gtk.Builder.Object] Gtk.HBox BitwiseOperationsHBox; [Gtk.Builder.Object] Gtk.Label SourceLabel; [Gtk.Builder.Object] Gtk.EventBox SourceLabelEB; [Gtk.Builder.Object] Gtk.Button DoOperationButton; [Gtk.Builder.Object] Gtk.ComboBox OperationComboBox; [Gtk.Builder.Object] Gtk.ComboBox OperandAsComboBox; [Gtk.Builder.Object] Gtk.Entry OperandEntry; [Gtk.Builder.Object] Gtk.Button CloseButton; DataBook dataBook; int numberBase; Gtk.Action performAction; enum OperandAsComboIndex { Hexadecimal, Decimal, Octal, Binary, Text } public enum OperationType { And, Or, Xor, Not } /// /// The number base to use for displaying the source range /// public int SourceLabelNumberBase { set { numberBase = value; if (dataBook.NPages > 0) { DataView curdv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; Update(curdv); } } get { return numberBase; } } public BitwiseOperationsWidget(DataBook db, Gtk.Action action) { dataBook = db; performAction = action; Gtk.Builder builder = new Gtk.Builder(); builder.AddFromFile(FileResourcePath.GetDataPath("ui", "BitwiseOperationsPlugin.ui")); builder.Autoconnect(this); OperationComboBox.Active = 0; OperandAsComboBox.Active = 0; numberBase = 16; // set button sensitivity OnOperandEntryChanged(null, null); this.Shown += OnWidgetShown; this.Add(BitwiseOperationsHBox); this.ShowAll(); } /// /// Whether a widget in the Widget has the focus /// bool IsFocusInWidget() { foreach (Gtk.Widget child in BitwiseOperationsHBox.Children) { Widget realChild = child; if (child.GetType() == typeof(Gtk.Alignment)) realChild = (child as Gtk.Alignment).Child; if (realChild.HasFocus) return true; } return false; } void OnOperandEntryChanged(object o, EventArgs args) { if (OperandEntry.Text.Length > 0) { DoOperationButton.Sensitive = true; performAction.Sensitive = true; } else { DoOperationButton.Sensitive = false; performAction.Sensitive = false; } } void OnOperandEntryActivated(object o, EventArgs args) { if (DoOperationButton.Sensitive == true) DoOperationButton.Click(); } void OnOperationComboBoxChanged(object o, EventArgs args) { if ((OperationType)OperationComboBox.Active == OperationType.Not) { OperandEntry.Sensitive = false; OperandAsComboBox.Sensitive = false; DoOperationButton.Sensitive = true; performAction.Sensitive = true; } else { OperandEntry.Sensitive = true; OperandAsComboBox.Sensitive = true; OnOperandEntryChanged(null, null); } } /// /// Parse the operand according to the selected type /// byte[] ParseOperand() { byte[] ba; string str = OperandEntry.Text; switch ((OperandAsComboIndex)OperandAsComboBox.Active) { case OperandAsComboIndex.Hexadecimal: ba = ByteArray.FromString(str, 16); break; case OperandAsComboIndex.Decimal: ba = ByteArray.FromString(str, 10); break; case OperandAsComboIndex.Octal: ba = ByteArray.FromString(str, 8); break; case OperandAsComboIndex.Binary: ba = ByteArray.FromString(str, 2); break; case OperandAsComboIndex.Text: ba = Encoding.ASCII.GetBytes(str); break; default: ba = new byte[0]; break; } return ba; } void OnDoOperationClicked(object o, EventArgs args) { if (dataBook.NPages == 0) return; DataView dv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; // get the operands as a byte array byte[] byteArray = null; try { byteArray = ParseOperand(); } catch (FormatException e) { ErrorAlert ea = new ErrorAlert(Catalog.GetString("Error in Operand"), e.Message, null); ea.Run(); ea.Destroy(); return; } /// get the range to apply the operation to Util.Range range = dv.Selection; if (range.IsEmpty()) { Util.Range bbRange = dv.Buffer.Range; range.Start = dv.CursorOffset; range.End = range.Start + byteArray.Length - 1; range.Intersect(bbRange); } // don't allow buffer modification while the operation is perfoming dv.Buffer.ModifyAllowed = false; dv.Buffer.FileOperationsAllowed = false; BitwiseOperation bo = new BitwiseOperation(dv.Buffer, byteArray, range, (OperationType)OperationComboBox.Active, Services.UI.Progress.NewCallback(), BitwiseOperationAsyncCallback, true); // start operation thread Thread boThread = new Thread(bo.OperationThread); boThread.IsBackground = true; boThread.Start(); } /// /// Called when an asynchronous operation finishes. /// void BitwiseOperationAsyncCallback(IAsyncResult ar) { BitwiseOperation state = (BitwiseOperation)ar.AsyncState; ThreadedAsyncOperation.OperationResult result = state.Result; // allow changes to the buffer state.Buffer.ModifyAllowed = true; state.Buffer.FileOperationsAllowed = true; switch (result) { case ThreadedAsyncOperation.OperationResult.Finished: break; case ThreadedAsyncOperation.OperationResult.Cancelled: state.Buffer.Undo(); break; case ThreadedAsyncOperation.OperationResult.CaughtException: break; default: break; } } /// /// Update the source range label /// public void Update(DataView dv) { if (dv == null) return; string str; if (dv.Selection.IsEmpty()) { string off1 = BaseConverter.ConvertToString(dv.CursorOffset, numberBase, true, true, 1); str = string.Format("({0},{1})", off1, off1); } else { string off1 = BaseConverter.ConvertToString(dv.Selection.Start, numberBase, true, true, 1); string off2 = BaseConverter.ConvertToString(dv.Selection.End, numberBase, true, true, 1); str = string.Format("({0},{1})", off1, off2); } SourceLabel.Text = str; } public void PerformOperation() { DoOperationButton.Click(); } void OnWidgetShown(object o, EventArgs args) { OperandEntry.GrabFocus(); } protected override bool OnKeyPressEvent(Gdk.EventKey e) { if (e.Key == Gdk.Key.Escape) { CloseButton.Click(); return true; } else return base.OnKeyPressEvent(e); } /// /// Handle the button press events on the source range label (cycles number bases) /// void OnSourceLabelButtonPress(object o, ButtonPressEventArgs args) { Gdk.EventButton e = args.Event; // ignore double and triple-clicks if (e.Type != Gdk.EventType.ButtonPress) return; // cycle 8, 10 and 16 number bases if (this.SourceLabelNumberBase == 8) this.SourceLabelNumberBase = 10; else if (this.SourceLabelNumberBase == 10) this.SourceLabelNumberBase = 16; else if (this.SourceLabelNumberBase == 16) this.SourceLabelNumberBase = 8; } void OnCloseButtonClicked(object o, EventArgs args) { // give focus to active dataview if the widget has it if (dataBook.NPages > 0 && IsFocusInWidget()) { DataViewDisplay curdvd = (DataViewDisplay)dataBook.CurrentPageWidget; curdvd.GrabKeyboardFocus(); } this.Hide(); } } /// /// Performs a bitwise operation using an asynchronous threaded model /// public class BitwiseOperation : ThreadedAsyncOperation { protected ByteBuffer byteBuffer; byte[] byteArray; Util.Range range; long currentOffset; BitwiseOperationsWidget.OperationType operationType; public ByteBuffer Buffer { get { return byteBuffer; } } public BitwiseOperation(ByteBuffer bb, byte[] ba, Util.Range range, BitwiseOperationsWidget.OperationType ot, ProgressCallback pc, AsyncCallback ac, bool glibIdle): base(pc, ac, glibIdle) { byteBuffer = bb; byteArray = ba; this.range = range; operationType = ot; currentOffset = range.Start; } protected override bool StartProgress() { progressCallback(string.Format("Applying operation"), ProgressAction.Message); return progressCallback(((double)currentOffset - range.Start) / range.Size, ProgressAction.Show); } protected override bool UpdateProgress() { return progressCallback(((double)currentOffset - range.Start) / range.Size, ProgressAction.Update); } protected override bool EndProgress() { return progressCallback(((double)currentOffset - range.Start) / range.Size, ProgressAction.Destroy); } protected override void DoOperation() { byteBuffer.BeginActionChaining(); if (range.IsEmpty()) return; // create the operand array // this is either the original byte array // or a new array containing multiple copies of the original byte[] operandArray; if (byteArray.Length > 0) { long numberOfRepetitions = range.Size / byteArray.Length; // too many repetitions... create new array if (numberOfRepetitions > 1024) { int len = ((4096 / byteArray.Length) + 1) * byteArray.Length; operandArray = new byte[len]; FillWithPattern(operandArray, byteArray); } else // use old array operandArray = byteArray; } else { // we have no operand eg when the operation is a NOT operandArray = new byte[4096]; } // the array to keep the results of the operation byte[] resultArray = new byte[operandArray.Length]; long left = range.Size; currentOffset = range.Start; while (left > 0 && !cancelled) { int min = (int)((left < resultArray.Length) ? left : resultArray.Length); // fill result array // ...more efficient way needed, perhaps implement bb.Read for (int i = 0; i < min; i++) resultArray[i] = byteBuffer[currentOffset + i]; // perform the operation on the data DoOperation(resultArray, operandArray, min); lock (byteBuffer.LockObj) { byteBuffer.ModifyAllowed = true; // write the changed data back byteBuffer.Replace(currentOffset, currentOffset + min - 1, resultArray, 0, min); byteBuffer.ModifyAllowed = false; } currentOffset += min; left -= min; } } protected override void EndOperation() { byteBuffer.EndActionChaining(); } /// /// Fill the dest array with the data found in the pattern array /// void FillWithPattern(byte[] dest, byte[] pattern) { if (pattern.Length == 0) return; int left = dest.Length; int offset = 0; while (left > 0) { int min = left < pattern.Length ? left : pattern.Length; Array.Copy(pattern, 0, dest, offset, min); offset += min; left -= min; } } /// /// Perform the operation ba1[i] = ba1[i] op ba2[i] /// void DoOperation(byte[] ba1, byte[] ba2, int length) { switch (operationType) { case BitwiseOperationsWidget.OperationType.And: for (int i = 0; i < length; i++) ba1[i] = (byte)(ba1[i] & ba2[i]); break; case BitwiseOperationsWidget.OperationType.Or: for (int i = 0; i < length; i++) ba1[i] = (byte)(ba1[i] | ba2[i]); break; case BitwiseOperationsWidget.OperationType.Xor: for (int i = 0; i < length; i++) ba1[i] = (byte)(ba1[i] ^ ba2[i]); break; case BitwiseOperationsWidget.OperationType.Not: for (int i = 0; i < length; i++) ba1[i] = (byte)(~ba1[i]); break; default: break; } } } } // namespace bless-0.6.3/src/gui/plugins/ConversionTablePlugin.cs000066400000000000000000000317571374060072200225050ustar00rootroot00000000000000// created on 2/18/2005 at 3:24 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.Text; using Gtk; using Bless.Util; using Bless.Tools; using Bless.Gui; using Bless.Buffers; using Bless.Plugins; using Mono.Unix; namespace Bless.Gui.Plugins { public class ConversionTablePlugin : GuiPlugin { DataBook dataBook; ConversionTable widget; Window mainWindow; ToggleAction conversionTableAction; UIManager uiManager; const string uiXml = "" + " " + " " + " " + ""; public ConversionTablePlugin(Window mw, UIManager uim) { mainWindow = mw; uiManager = uim; name = "ConversionTable"; author = "Alexandros Frantzis"; description = "Convert"; } public override bool Load() { dataBook = (DataBook)GetDataBook(mainWindow); widget = new ConversionTable(dataBook); WidgetGroup wg1 = (WidgetGroup)GetWidgetGroup(mainWindow, 1); wg1.Add(widget); AddMenuItems(uiManager); Preferences.Proxy.Subscribe("Tools.ConversionTable.Show", "ct1", new PreferencesChangedHandler(OnPreferencesChanged)); loaded = true; return true; } private void AddMenuItems(UIManager uim) { ToggleActionEntry[] toggleActionEntries = new ToggleActionEntry[] { new ToggleActionEntry ("ConversionTableAction", null, Catalog.GetString("Conversion Table"), null, null, new EventHandler(OnViewConversionTableToggled), false), }; ActionGroup group = new ActionGroup ("ConversionTableActions"); group.Add (toggleActionEntries); uim.InsertActionGroup(group, 0); uim.AddUiFromString(uiXml); conversionTableAction = (ToggleAction)uim.GetAction("/menubar/Tools/ConversionTable"); uim.EnsureUpdate(); } ///Handle the View->Conversion Table command public void OnViewConversionTableToggled(object o, EventArgs args) { Preferences.Proxy.Change("Tools.ConversionTable.Show", conversionTableAction.Active.ToString(), "ct1"); } void OnPreferencesChanged(Preferences prefs) { if (prefs["Tools.ConversionTable.Show"] == "True") conversionTableAction.Active = true; else conversionTableAction.Active = false; } } /// A widget to convert the data at the current offset to various types public class ConversionTable: Gtk.HBox { [Gtk.Builder.Object] Gtk.Table ConversionTableWidget; [Gtk.Builder.Object] Gtk.Entry Signed8bitEntry; [Gtk.Builder.Object] Gtk.Entry Unsigned8bitEntry; [Gtk.Builder.Object] Gtk.Entry Signed16bitEntry; [Gtk.Builder.Object] Gtk.Entry Unsigned16bitEntry; [Gtk.Builder.Object] Gtk.Entry Signed32bitEntry; [Gtk.Builder.Object] Gtk.Entry Unsigned32bitEntry; [Gtk.Builder.Object] Gtk.Entry Float32bitEntry; [Gtk.Builder.Object] Gtk.Entry Float64bitEntry; [Gtk.Builder.Object] Gtk.Entry HexadecimalEntry; [Gtk.Builder.Object] Gtk.Entry DecimalEntry; [Gtk.Builder.Object] Gtk.Entry OctalEntry; [Gtk.Builder.Object] Gtk.Entry BinaryEntry; [Gtk.Builder.Object] Gtk.Entry AsciiEntry; [Gtk.Builder.Object] Gtk.CheckButton LittleEndianCheckButton; [Gtk.Builder.Object] Gtk.CheckButton UnsignedAsHexCheckButton; DataBook dataBook; bool littleEndian; bool unsignedAsHex; public ConversionTable(DataBook db) { Gtk.Builder builder = new Gtk.Builder(); builder.AddFromFile(FileResourcePath.GetDataPath("ui", "ConversionTablePlugin.ui")); builder.Autoconnect(this); littleEndian = true; unsignedAsHex = false; dataBook = db; foreach(DataViewDisplay dvd in dataBook.Children) { OnDataViewAdded(dvd.View); } dataBook.PageAdded += new DataView.DataViewEventHandler(OnDataViewAdded); dataBook.Removed += new RemovedHandler(OnDataViewRemoved); dataBook.SwitchPage += new SwitchPageHandler(OnSwitchPage); Preferences.Proxy.Subscribe("Tools.ConversionTable.Show", "ct2", new PreferencesChangedHandler(OnPreferencesChanged)); this.Add(ConversionTableWidget); this.ShowAll(); } void OnDataViewAdded(DataView dv) { dv.Buffer.Changed += new ByteBuffer.ChangedHandler(OnBufferContentsChanged); dv.BufferChanged += new DataView.DataViewEventHandler(OnBufferChanged); dv.CursorChanged += new DataView.DataViewEventHandler(OnCursorChanged); } void OnDataViewRemoved(object o, RemovedArgs args) { DataView dv = ((DataViewDisplay)args.Widget).View; dv.Buffer.Changed -= new ByteBuffer.ChangedHandler(OnBufferContentsChanged); dv.BufferChanged -= new DataView.DataViewEventHandler(OnBufferChanged); dv.CursorChanged -= new DataView.DataViewEventHandler(OnCursorChanged); Update(); } void OnBufferChanged(DataView dv) { // if changed dataview is not the current one just ignore DataViewDisplay dvd = (DataViewDisplay)dataBook.CurrentPageWidget; if (dvd == null || dvd.View != dv) return; Update(); } void OnBufferContentsChanged(ByteBuffer bb) { Gtk.Application.Invoke(delegate { DataView dv = null; // find DataView that owns bb foreach (DataViewDisplay dvtemp in dataBook.Children) { if (dvtemp.View.Buffer == bb) { dv = dvtemp.View; break; } } DataViewDisplay dvd = (DataViewDisplay)dataBook.CurrentPageWidget; if (dvd == null || dvd.View != dv) return; Update(); }); } void OnSwitchPage(object o, SwitchPageArgs args) { Update(); } void OnCursorChanged(DataView dv) { DataView dvcur = ((DataViewDisplay)dataBook.CurrentPageWidget).View; if (dvcur != dv) return; Update(); } // redefine Hide() method // to properly handle hiding protected override void OnHidden() { // if the focus is in the table // give it to the active dataview if (IsFocusInTable()) { DataViewDisplay dvd = (DataViewDisplay)dataBook.CurrentPageWidget; if (dvd != null) dvd.GrabKeyboardFocus(); } Preferences.Proxy.Change("Tools.ConversionTable.Show", "False", "ct2"); base.OnHidden(); } protected override void OnShown() { Preferences.Proxy.Change("Tools.ConversionTable.Show", "True", "ct2"); base.OnShown(); Update(); } // whether a widget in the table has the focus bool IsFocusInTable() { foreach (Gtk.Widget child in ConversionTableWidget.Children) { Widget realChild = child; if (child.GetType() == typeof(Gtk.Alignment)) realChild = (child as Gtk.Alignment).Child; if (realChild.HasFocus) return true; } return false; } void OnLittleEndianToggled(object o, EventArgs args) { littleEndian = LittleEndianCheckButton.Active; Preferences.Proxy.Change("Tools.ConversionTable.LEDecoding", littleEndian.ToString(), "ct2"); Update(); } void OnUnsignedAsHexToggled(object o, EventArgs args) { unsignedAsHex = UnsignedAsHexCheckButton.Active; Preferences.Proxy.Change("Tools.ConversionTable.UnsignedAsHex", unsignedAsHex.ToString(), "ct2"); Update(); } void OnPreferencesChanged(Preferences prefs) { if (prefs["Tools.ConversionTable.LEDecoding"] == "True") LittleEndianCheckButton.Active = true; else LittleEndianCheckButton.Active = false; if (prefs["Tools.ConversionTable.UnsignedAsHex"] == "True") UnsignedAsHexCheckButton.Active = true; else UnsignedAsHexCheckButton.Active = false; if (prefs["Tools.ConversionTable.Show"] == "True") this.Visible = true; else this.Visible = false; } void OnCloseButtonClicked(object o, EventArgs args) { Preferences.Instance["Tools.ConversionTable.Show"] = "False"; } void Clear8bit() { Signed8bitEntry.Text = "---"; Unsigned8bitEntry.Text = "---"; } void Clear16bit() { Signed16bitEntry.Text = "---"; Unsigned16bitEntry.Text = "---"; } void Clear32bit() { Signed32bitEntry.Text = "---"; Unsigned32bitEntry.Text = "---"; } void ClearFloat() { Float32bitEntry.Text = "---"; Float64bitEntry.Text = "---"; } void ClearBases() { HexadecimalEntry.Text = "---"; DecimalEntry.Text = "---"; OctalEntry.Text = "---"; BinaryEntry.Text = "---"; AsciiEntry.Text = "---"; } ///Update the 8bit entries void Update8bit(DataView dv) { long offset = dv.CursorOffset; // make sure offset is valid if (offset < dv.Buffer.Size && offset >= 0) { byte uval = dv.Buffer[offset]; sbyte val = (sbyte)uval; // set signed Signed8bitEntry.Text = val.ToString(); // set unsigned if (unsignedAsHex) Unsigned8bitEntry.Text = string.Format("0x{0:x}", uval); else Unsigned8bitEntry.Text = uval.ToString(); } else { Clear8bit(); } } ///Update the 16bit entries void Update16bit(DataView dv) { long offset = dv.CursorOffset; // make sure offset is valid if (offset < dv.Buffer.Size - 1 && offset >= 0) { short val = 0; // create value according to endianess if (littleEndian) { val += (short)(dv.Buffer[offset+1] << 8); val += (short)dv.Buffer[offset]; } else { val += (short)(dv.Buffer[offset] << 8); val += (short)dv.Buffer[offset+1]; } ushort uval = (ushort)val; // set signed Signed16bitEntry.Text = val.ToString(); // set unsigned if (unsignedAsHex) Unsigned16bitEntry.Text = string.Format("0x{0:x}", uval); else Unsigned16bitEntry.Text = uval.ToString(); } else { Clear16bit(); } } ///Update the 32bit entries void Update32bit(DataView dv) { long offset = dv.CursorOffset; // make sure offset is valid if (offset < dv.Buffer.Size - 3 && offset >= 0) { int val = 0; // create value according to endianess if (littleEndian) { val += dv.Buffer[offset+3] << 24; val += dv.Buffer[offset+2] << 16; val += dv.Buffer[offset+1] << 8; val += dv.Buffer[offset]; } else { val += dv.Buffer[offset] << 24; val += dv.Buffer[offset+1] << 16; val += dv.Buffer[offset+2] << 8; val += dv.Buffer[offset+3]; } uint uval = (uint)val; // set signed Signed32bitEntry.Text = val.ToString(); // set unsigned if (unsignedAsHex) Unsigned32bitEntry.Text = string.Format("0x{0:x}", uval); else Unsigned32bitEntry.Text = uval.ToString(); } else { Clear32bit(); } } ///Update the floating point entries void UpdateFloat(DataView dv) { long offset = dv.CursorOffset; // make sure offset is valid for 32 bit float (and 64 bit) if (offset < dv.Buffer.Size - 3 && offset >= 0) { // create byte[] with float bytes byte[] ba = new byte[8]; // fill byte[] according to endianess if (littleEndian) for (int i = 0; i < 4; i++) ba[i] = dv.Buffer[offset+i]; else for (int i = 0; i < 4; i++) ba[3-i] = dv.Buffer[offset+i]; // set float 32bit float f = BitConverter.ToSingle(ba, 0); Float32bitEntry.Text = f.ToString(); // make sure offset is valid for 64 bit float if (offset < dv.Buffer.Size - 7) { // fill byte[] according to endianess if (littleEndian) for (int i = 4; i < 8; i++) ba[i] = dv.Buffer[offset+i]; else for (int i = 0; i < 8; i++) ba[7-i] = dv.Buffer[offset+i]; // set float 64bit double d = BitConverter.ToDouble(ba, 0); Float64bitEntry.Text = d.ToString(); } else Float64bitEntry.Text = "---"; } else { ClearFloat(); } } ///Update the number base entries void UpdateBases(DataView dv) { long offset = dv.CursorOffset; long size; if (offset < 0 || offset >= dv.Buffer.Size) size = 0; else { size = dv.Buffer.Size - offset; size = size < 4 ? size : 4; } byte[] ba = new byte[(int)size]; for (int i = 0; i < size; i++) ba[i] = dv.Buffer[offset+i]; // make sure offset is valid if (size > 0) { HexadecimalEntry.Text = ByteArray.ToString(ba, 16); DecimalEntry.Text = ByteArray.ToString(ba, 10); OctalEntry.Text = ByteArray.ToString(ba, 8); BinaryEntry.Text = ByteArray.ToString(ba, 2); AsciiEntry.Text = Encoding.ASCII.GetString(ba); } else { ClearBases(); } } ///Update all conversion entries public void Update() { if (!this.Visible) return; DataViewDisplay dvd = (DataViewDisplay)dataBook.CurrentPageWidget; if (dvd == null) { Clear(); return; } DataView dv = dvd.View; Update8bit(dv); Update16bit(dv); Update32bit(dv); UpdateFloat(dv); UpdateBases(dv); } ///Clear all conversion entries public void Clear() { if (!this.Visible) return; Clear8bit(); Clear16bit(); Clear32bit(); ClearFloat(); ClearBases(); } } } // end namespace bless-0.6.3/src/gui/plugins/CopyOffsetPlugin.cs000066400000000000000000000137671374060072200214720ustar00rootroot00000000000000/* * Copyright (c) 2019, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using Gtk; using Bless.Plugins; using Bless.Tools; using Bless.Util; using Mono.Unix; namespace Bless.Gui.Plugins { public class CopyOffsetPlugin : GuiPlugin { Gtk.Action CopyOffsetAction; const string uiXml = "" + " " + " " + " " + " " + " " + "" + "" + " " + " " + " " + ""; DataBook dataBook; Window mainWindow; UIManager uiManager; IPluginPreferences pluginPreferences; int number_base; static TargetEntry[] clipboardTargets = new TargetEntry[] { new TargetEntry("UTF8_STRING", 0, 0) }; Gtk.Clipboard clipboard; long saved_offset; Bless.Util.Range saved_selection; public CopyOffsetPlugin(Window mw, UIManager uim) { mainWindow = mw; uiManager = uim; pluginPreferences = new CopyOffsetPreferences(); number_base = 10; saved_offset = 0; saved_selection = new Bless.Util.Range(); name = "CopyOffset"; author = "Alexandros Frantzis"; description = "Adds to copy the current offset (or range)"; loadAfter.Add("EditOperations"); } public override bool Load() { clipboard = Gtk.Clipboard.Get(Gdk.Atom.Intern("CLIPBOARD", true)); dataBook = (DataBook)GetDataBook(mainWindow); Preferences.Proxy.Subscribe("CopyOffset.NumberBase", "co", new PreferencesChangedHandler(OnPreferencesChanged)); AddActions(uiManager); loaded = true; return true; } private void AddActions(UIManager uim) { ActionEntry[] actionEntries = new ActionEntry[] { new ActionEntry("CopyOffsetAction", Stock.Copy, Catalog.GetString("Copy Offset(s)"), "C", null, new EventHandler(OnCopyOffsetActivated)) }; ActionGroup group = new ActionGroup("CopyOffsetActions"); group.Add (actionEntries); uim.InsertActionGroup(group, 0); uim.AddUiFromString(uiXml); uim.EnsureUpdate(); } private void OnCopyOffsetActivated(object o, EventArgs args) { if (dataBook.NPages == 0) return; DataView dv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; saved_offset = dv.CursorOffset; saved_selection = dv.Selection; clipboard.SetWithData(clipboardTargets, new ClipboardGetFunc(OnClipboardGet), new ClipboardClearFunc(OnClipboardClear)); } private void OnClipboardGet(Clipboard cb, SelectionData sd, uint n) { if (saved_selection.IsEmpty()) { sd.Text = BaseConverter.ConvertToString(saved_offset, number_base, true, true, 1); } else { string start = BaseConverter.ConvertToString(saved_selection.Start, number_base, true, true, 1); string end = BaseConverter.ConvertToString(saved_selection.End, number_base, true, true, 1); sd.Text = string.Format("{0},{1}", start, end); } } private void OnClipboardClear(Clipboard cb) { } public override IPluginPreferences PluginPreferences { get { return pluginPreferences; } } void OnPreferencesChanged(Preferences prefs) { try { number_base = (int) BaseConverter.ConvertToNum(prefs["CopyOffset.NumberBase"], 10); } catch { number_base = 10; } if (number_base != 2 && number_base != 8 && number_base != 10 && number_base != 16) number_base = 10; } } class CopyOffsetPreferences : IPluginPreferences { CopyOffsetPreferencesWidget preferencesWidget; public Widget Widget { get { if (preferencesWidget == null) InitWidget(); return preferencesWidget; } } public void LoadPreferences() { if (preferencesWidget == null) InitWidget(); string base_str = Preferences.Instance["CopyOffset.NumberBase"]; try { preferencesWidget.ActiveBase = (int) BaseConverter.ConvertToNum(base_str, 10); } catch { preferencesWidget.ActiveBase = 10; } } public void SavePreferences() { } void InitWidget() { preferencesWidget = new CopyOffsetPreferencesWidget(); preferencesWidget.NumberBaseCombo.Changed += OnNumberBaseChanged; } void OnNumberBaseChanged(object o, EventArgs args) { Preferences.Instance["CopyOffset.NumberBase"] = preferencesWidget.NumberBaseCombo.ActiveText; } } class CopyOffsetPreferencesWidget : Gtk.VBox { Gtk.ComboBox numberBaseCombo; int BaseToActiveIndex(int number_base) { switch (number_base) { case 2: return 0; case 8: return 1; case 10: return 2; case 16: return 3; default: throw new Exception(); } } public Gtk.ComboBox NumberBaseCombo { get { return numberBaseCombo; } } public int ActiveBase { set { numberBaseCombo.Active = BaseToActiveIndex(value); } } public CopyOffsetPreferencesWidget() { // Use a hbox inside an vbox to avoid expanding vertically. Gtk.HBox hbox = new Gtk.HBox(); Gtk.Label label = new Gtk.Label(Catalog.GetString("Number base:")); numberBaseCombo = Gtk.ComboBox.NewText(); numberBaseCombo.AppendText("2"); numberBaseCombo.AppendText("8"); numberBaseCombo.AppendText("10"); numberBaseCombo.AppendText("16"); hbox.PackStart(label, false, false, 6); hbox.PackStart(numberBaseCombo, false, false, 6); this.PackStart(hbox, true, false, 6); this.ShowAll(); } } } //end namespace bless-0.6.3/src/gui/plugins/EditOperationsPlugin.cs000066400000000000000000000252001374060072200223230ustar00rootroot00000000000000// created on 4/30/2006 at 12:59 PM /* * Copyright (c) 2006, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.IO; using Gtk; using Bless.Buffers; using Bless.Gui; using Bless.Plugins; using Bless.Gui.Dialogs; using Bless.Tools; namespace Bless.Gui.Plugins { public class EditOperationsPlugin : GuiPlugin { Gtk.Action UndoAction; Gtk.Action RedoAction; Gtk.Action CutAction; Gtk.Action CopyAction; Gtk.Action PasteAction; Gtk.Action DeleteAction; const string uiXml = "" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + "" + "" + " " + " " + " " + " " + " " + " " + " " + " " + "" + "" + " " + " " + " " + " " + " " + " " + ""; DataBook dataBook; Window mainWindow; UIManager uiManager; ActionGroup editActionGroup; int editAccelCount = 0; public EditOperationsPlugin(Window mw, UIManager uim) { mainWindow = mw; uiManager = uim; name = "EditOperations"; author = "Alexandros Frantzis"; description = "Provides access to basic edit operations"; } public override bool Load() { dataBook = (DataBook)GetDataBook(mainWindow); AddActions(uiManager); dataBook.PageAdded += new DataView.DataViewEventHandler(OnDataViewAdded); dataBook.PageRemoved += new DataView.DataViewEventHandler(OnDataViewRemoved); dataBook.SwitchPage += new SwitchPageHandler(OnSwitchPage); loaded = true; return true; } void OnDataViewAdded(DataView dv) { dv.Buffer.Changed += new ByteBuffer.ChangedHandler(OnBufferContentsChanged); dv.BufferChanged += new DataView.DataViewEventHandler(OnBufferChanged); dv.FocusChanged += new DataView.DataViewEventHandler(OnDataViewFocusChanged); } void OnDataViewRemoved(DataView dv) { dv.Buffer.Changed -= new ByteBuffer.ChangedHandler(OnBufferContentsChanged); dv.BufferChanged -= new DataView.DataViewEventHandler(OnBufferChanged); dv.FocusChanged -= new DataView.DataViewEventHandler(OnDataViewFocusChanged); // if there are no pages left update the menu if (dataBook.NPages == 0) UpdateActions(null); } void OnBufferChanged(DataView dv) { UpdateActions(dv); } void OnBufferContentsChanged(ByteBuffer bb) { Gtk.Application.Invoke(delegate { DataView dv = null; // find DataView that owns bb foreach (DataViewDisplay dvtemp in dataBook.Children) { if (dvtemp.View.Buffer == bb) { dv = dvtemp.View; break; } } UpdateActions(dv); }); } void OnSwitchPage(object o, SwitchPageArgs args) { DataView dv = ((DataViewDisplay)dataBook.GetNthPage((int)args.PageNum)).View; UpdateActions(dv); } void ConnectEditAccelerators(bool v) { if (editAccelCount == 0 && v == true) { foreach(Gtk.Action a in editActionGroup.ListActions()) a.ConnectAccelerator(); editAccelCount = 1; } else if (editAccelCount == 1 && v == false) { foreach(Gtk.Action a in editActionGroup.ListActions()) a.DisconnectAccelerator(); editAccelCount = 0; } } void OnDataViewFocusChanged(DataView dv) { // if a DataView gained the focus // enable Edit Menu Accelerators if (dv.Display.HasFocus) { ConnectEditAccelerators(true); } else { // disable them, so that key combos in other // widgets behave correctly (eg Ctrl+C in Text Entries) ConnectEditAccelerators(false); } } private void AddActions(UIManager uim) { ActionEntry[] actionEntries = new ActionEntry[] { new ActionEntry ("CutAction", Stock.Cut, null, "X", null, new EventHandler(OnCutActivated)), new ActionEntry ("CopyAction", Stock.Copy, null, "C", "Copy", new EventHandler(OnCopyActivated)), new ActionEntry ("PasteAction", Stock.Paste, null, "V", "Paste", new EventHandler(OnPasteActivated)), new ActionEntry ("DeleteAction", Stock.Delete, null, "Delete", "Delete", new EventHandler(OnDeleteActivated)) }; ActionEntry[] miscActionEntries = new ActionEntry[] { new ActionEntry ("UndoAction", Stock.Undo, null, "Z", "Undo", new EventHandler(OnUndoActivated)), new ActionEntry ("RedoAction", Stock.Redo, null, "Z", "Redo", new EventHandler(OnRedoActivated)), new ActionEntry ("PreferencesAction", Stock.Preferences, null, null, "Preferences", new EventHandler(OnPreferencesActivated)) }; editActionGroup = new ActionGroup("EditActions"); editActionGroup.Add (actionEntries); ActionGroup miscActionGroup = new ActionGroup ("MiscEditActions"); miscActionGroup.Add (miscActionEntries); uim.InsertActionGroup(editActionGroup, 0); uim.InsertActionGroup(miscActionGroup, 0); uim.AddUiFromString(uiXml); UndoAction = (Gtk.Action)uim.GetAction("/menubar/Edit/Undo"); RedoAction = (Gtk.Action)uim.GetAction("/menubar/Edit/Redo"); CutAction = (Gtk.Action)uim.GetAction("/menubar/Edit/Cut"); CopyAction = (Gtk.Action)uim.GetAction("/menubar/Edit/Copy"); PasteAction = (Gtk.Action)uim.GetAction("/menubar/Edit/Paste"); DeleteAction = (Gtk.Action)uim.GetAction("/menubar/Edit/Delete"); foreach (Gtk.Action a in editActionGroup.ListActions()) { // for some reason the accelerators are connected twice // ... so disconnect them twice for (int i = 0; i < 2; i++) a.DisconnectAccelerator(); } editAccelCount = 0; uim.EnsureUpdate(); } ///Handle edit->undo command from menu public void OnUndoActivated(object o, EventArgs args) { if (dataBook.NPages == 0) return; DataView dv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; dv.Undo(); } ///Handle edit->redo command from menu public void OnRedoActivated(object o, EventArgs args) { if (dataBook.NPages == 0) return; DataView dv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; dv.Redo(); } ///Handle edit->cut command from menu public void OnCutActivated(object o, EventArgs args) { if (dataBook.NPages == 0) return; DataView dv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; dv.Cut(); } ///Handle edit->copy command from menu public void OnCopyActivated(object o, EventArgs args) { if (dataBook.NPages == 0) return; DataView dv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; dv.Copy(); } ///Handle edit->paste command from menu public void OnPasteActivated(object o, EventArgs args) { if (dataBook.NPages == 0) return; DataView dv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; dv.Paste(); } ///Handle edit->delete command from menu public void OnDeleteActivated(object o, EventArgs args) { if (dataBook.NPages == 0) return; DataView dv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; dv.Delete(); } ///Handle edit->Select Range command from menu public void OnSelectRange(object o, EventArgs args) { if (dataBook.NPages == 0) return; //DataView dv=((DataViewDisplay)dataBook.CurrentPageWidget).View; //selectRangeWidget.Show(); } ///Handle edit->preferences command from menu public void OnPreferencesActivated(object o, EventArgs args) { PreferencesDialog pd = new PreferencesDialog(mainWindow); pd.Show(); } /// /// Updates various menu items according to the ModifyAllowed /// permission property of the active ByteBuffer /// void UpdateActions(DataView dv) { if (dv == null) { CutAction.Sensitive = false; PasteAction.Sensitive = false; DeleteAction.Sensitive = false; UndoAction.Sensitive = false; RedoAction.Sensitive = false; CopyAction.Sensitive = false; return; } DataView curdv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; ByteBuffer curbb = curdv.Buffer; ByteBuffer bb = dv.Buffer; // if DataView is active if (curbb == bb) { // gray various menu items // if we are not allowed to modify the buffer if (!bb.ModifyAllowed) { CutAction.Sensitive = false; PasteAction.Sensitive = false; DeleteAction.Sensitive = false; } else { CutAction.Sensitive = true; PasteAction.Sensitive = true; DeleteAction.Sensitive = true; } // gray Undo if there is no undo action // or we aren't allowed to modify the file if (bb.CanUndo && bb.ModifyAllowed) { UndoAction.Sensitive = true; } else { UndoAction.Sensitive = false; } // gray Redo if there is no redo action // or we aren't allowed to modify the file if (bb.CanRedo && bb.ModifyAllowed) { RedoAction.Sensitive = true; } else { RedoAction.Sensitive = false; } // gray various menu items // if we are not allowed to read from the buffer if (!bb.ReadAllowed) { CopyAction.Sensitive = false; } else { CopyAction.Sensitive = true; } } } } } //end namespace bless-0.6.3/src/gui/plugins/FileExportPlugin.cs000066400000000000000000000061151374060072200214570ustar00rootroot00000000000000// created on 12/4/2006 at 1:50 AM /* * Copyright (c) 2006, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using Bless.Buffers; using Bless.Gui; using Bless.Plugins; using Bless.Gui.Dialogs; using Bless.Tools; using System; using System.IO; using Gtk; using Mono.Unix; namespace Bless.Gui.Plugins { public class FileExportPlugin : GuiPlugin { Gtk.Action ExportAction; const string uiXml = "" + " " + " " + " " + " " + " " + ""; DataBook dataBook; Window mainWindow; UIManager uiManager; ExportDialog exportDialog; public FileExportPlugin(Window mw, UIManager uim) { mainWindow = mw; uiManager = uim; name = "FileExport"; author = "Alexandros Frantzis"; description = "Export a file to various formats"; loadAfter.Add("FileOperations"); } public override bool Load() { dataBook = (DataBook) GetDataBook(mainWindow); AddMenuItems(uiManager); dataBook.PageRemoved += new DataView.DataViewEventHandler(OnDataViewRemoved); dataBook.SwitchPage += new SwitchPageHandler(OnSwitchPage); exportDialog = new ExportDialog(dataBook, mainWindow); loaded = true; return true; } void OnDataViewRemoved(DataView dv) { // if there are no pages left update the menu if (dataBook.NPages == 0) UpdateActions(null); } void OnSwitchPage(object o, SwitchPageArgs args) { DataView dv = ((DataViewDisplay)dataBook.GetNthPage((int)args.PageNum)).View; UpdateActions(dv); } private void AddMenuItems(UIManager uim) { ActionEntry[] actionEntries = new ActionEntry[] { new ActionEntry ("ExportAction", null, Catalog.GetString("_Export..."), null, null, new EventHandler(OnExportActivated)), }; ActionGroup group = new ActionGroup ("ExportActions"); group.Add (actionEntries); uim.InsertActionGroup(group, 0); uim.AddUiFromString(uiXml); ExportAction = uim.GetAction("/menubar/File/Extra/Export"); uim.EnsureUpdate(); } ///Handle file->export command from menu public void OnExportActivated(object o, EventArgs args) { exportDialog.Show(); } void UpdateActions(DataView dv) { if (dv == null) ExportAction.Sensitive = false; else ExportAction.Sensitive = true; } } } //end namespace bless-0.6.3/src/gui/plugins/FileOperationsPlugin.cs000066400000000000000000000230031374060072200223140ustar00rootroot00000000000000// created on 4/29/2006 at 2:39 PM /* * Copyright (c) 2006, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using Bless.Buffers; using Bless.Gui; using Bless.Plugins; using Bless.Gui.Dialogs; using Bless.Tools; using System; using System.IO; using Gtk; using Mono.Unix; namespace Bless.Gui.Plugins { public class FileOperationsPlugin : GuiPlugin { Gtk.Action SaveAction; Gtk.Action SaveAsAction; Gtk.Action CloseAction; Gtk.Action QuitAction; Gtk.Action RevertAction; const string uiXml = "" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + "" + "" + " " + " " + " " + " " + " " + ""; DataBook dataBook; Window mainWindow; UIManager uiManager; public FileOperationsPlugin(Window mw, UIManager uim) { mainWindow = mw; uiManager = uim; name = "FileOperations"; author = "Alexandros Frantzis"; description = "Provides access to basic file operations"; } public override bool Load() { dataBook = (DataBook)GetDataBook(mainWindow); AddActions(uiManager); dataBook.PageAdded += new DataView.DataViewEventHandler(OnDataViewAdded); dataBook.PageRemoved += new DataView.DataViewEventHandler(OnDataViewRemoved); dataBook.SwitchPage += new SwitchPageHandler(OnSwitchPage); loaded = true; return true; } void OnDataViewAdded(DataView dv) { dv.Buffer.PermissionsChanged += new ByteBuffer.ChangedHandler(OnBufferPermissionsChanged); dv.BufferChanged += new DataView.DataViewEventHandler(OnBufferChanged); } void OnDataViewRemoved(DataView dv) { dv.Buffer.PermissionsChanged -= new ByteBuffer.ChangedHandler(OnBufferPermissionsChanged); dv.BufferChanged -= new DataView.DataViewEventHandler(OnBufferChanged); // if there are no pages left update the menu if (dataBook.NPages == 0) UpdateActions(null); } void OnBufferChanged(DataView dv) { UpdateActions(dv); } void OnBufferPermissionsChanged(ByteBuffer bb) { Gtk.Application.Invoke(delegate { DataView dv = null; // find DataView that owns bb foreach (DataViewDisplay dvtemp in dataBook.Children) { if (dvtemp.View.Buffer == bb) { dv = dvtemp.View; break; } } UpdateActions(dv); }); } void OnSwitchPage(object o, SwitchPageArgs args) { DataView dv = ((DataViewDisplay)dataBook.GetNthPage((int)args.PageNum)).View; UpdateActions(dv); } private void AddActions(UIManager uim) { ActionEntry[] actionEntries = new ActionEntry[] { new ActionEntry ("NewAction", Stock.New, null, "N", "New File", new EventHandler(OnNewActivated)), new ActionEntry ("OpenAction", Stock.Open, null, "O", "Open File", new EventHandler(OnOpenActivated)), new ActionEntry ("SaveAction", Stock.Save, null, "S", "Save File", new EventHandler(OnSaveActivated)), new ActionEntry ("SaveAsAction", Stock.SaveAs, null, "S", "Save File As", new EventHandler(OnSaveAsActivated)), new ActionEntry ("RevertAction", Stock.RevertToSaved, null, null, "Revert File", new EventHandler(OnRevertActivated)), new ActionEntry ("CloseAction", Stock.Close, null, "W", "Close File", new EventHandler(OnCloseActivated)), new ActionEntry ("QuitAction", Stock.Quit, null, "Q", "Quit Application", new EventHandler(OnQuitActivated)) }; ActionGroup group = new ActionGroup ("FileActions"); group.Add (actionEntries); uim.InsertActionGroup(group, 0); uim.AddUiFromString(uiXml); SaveAction = (Gtk.Action)uim.GetAction("/menubar/File/Save"); SaveAsAction = (Gtk.Action)uim.GetAction("/menubar/File/SaveAs"); CloseAction = (Gtk.Action)uim.GetAction("/menubar/File/Close"); QuitAction = (Gtk.Action)uim.GetAction("/menubar/File/Quit"); RevertAction = (Gtk.Action)uim.GetAction("/menubar/File/Revert"); uim.EnsureUpdate(); } ///Handle file->new command from menu public void OnNewActivated(object o, EventArgs args) { ByteBuffer bb = Services.File.NewFile(); // create and setup a DataView DataView dv = Services.File.CreateDataView(bb); dataBook.AppendView(dv, new CloseViewDelegate(Services.File.CloseFile), Path.GetFileName(bb.Filename)); } ///Handle file->open command from menu public void OnOpenActivated(object o, EventArgs args) { // Get path of file(s) to open Gtk.FileChooserDialog fs = new Gtk.FileChooserDialog(Catalog.GetString("Open File(s)"), mainWindow, FileChooserAction.Open, Gtk.Stock.Cancel, ResponseType.Cancel, Gtk.Stock.Open, ResponseType.Accept); fs.SelectMultiple = true; ResponseType result = (ResponseType)fs.Run(); fs.Hide(); // if user does not cancel load the file(s) if (result == ResponseType.Accept) Services.File.LoadFiles(fs.Filenames); fs.Destroy(); } ///Handle file->save command from menu public void OnSaveActivated(object o, EventArgs args) { if (dataBook.NPages == 0) return; DataView dv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; Services.File.SaveFile(dv, null, false, false); } ///Handle file->save as command from menu public void OnSaveAsActivated(object o, EventArgs args) { if (dataBook.NPages == 0) return; DataView dv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; Services.File.SaveFile(dv, null, true, false); } ///Handle file->revert command from menu public void OnRevertActivated(object o, EventArgs args) { if (dataBook.NPages == 0) return; DataView dv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; RevertConfirmationAlert rca = new RevertConfirmationAlert(dv.Buffer.Filename, mainWindow); ResponseType response = (ResponseType)rca.Run(); rca.Destroy(); try { if (response == ResponseType.Ok) dv.Revert(); } catch (FileNotFoundException ex) { string msg = string.Format(Catalog.GetString("The file '{0}' cannot be found. Perhaps it has been recently deleted."), ex.Message); ErrorAlert ea = new ErrorAlert(Catalog.GetString("Error reverting file"), msg, mainWindow); ea.Run(); ea.Destroy(); } } ///Handle file->close as command from menu public void OnCloseActivated(object o, EventArgs args) { if (dataBook.NPages == 0) return; DataView dv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; Services.File.CloseFile(dv); } ///Handle file->quit command from menu public void OnQuitActivated(object o, EventArgs args) { Services.File.TryQuit(); } /// /// Updates various menu items according to the FileOperationsAllowed /// permission property of the active ByteBuffer /// void UpdateActions(DataView dv) { if (dv == null) { SaveAction.Sensitive = false; SaveAsAction.Sensitive = false; CloseAction.Sensitive = false; RevertAction.Sensitive = false; return; } DataView curdv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; ByteBuffer curbb = curdv.Buffer; ByteBuffer bb = dv.Buffer; // if DataView is active if (curbb == bb) { // gray various menu items // if FileOperations aren't allowed if (!bb.FileOperationsAllowed) { SaveAction.Sensitive = false; SaveAsAction.Sensitive = false; CloseAction.Sensitive = false; //SaveToolButton.Sensitive=false; } else { SaveAction.Sensitive = true; SaveAsAction.Sensitive = true; CloseAction.Sensitive = true; //SaveToolButton.Sensitive=true; } if (dv.Buffer.HasFile && dv.Buffer.ModifyAllowed) RevertAction.Sensitive = true; else RevertAction.Sensitive = false; } // If even one ByteBuffer in the dataBook // doesn't allow file operations // gray the Quit menu item. QuitAction.Sensitive = true; // set initially to true foreach (DataViewDisplay dd in dataBook.Children) { if (!dd.View.Buffer.FileOperationsAllowed) { QuitAction.Sensitive = false; dataBook.SetCloseSensitivity(dd, false); } else dataBook.SetCloseSensitivity(dd, true); } } } } bless-0.6.3/src/gui/plugins/FindReplacePlugin.cs000066400000000000000000000473021374060072200215550ustar00rootroot00000000000000// created on 6/15/2005 at 1:29 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using Gtk; using Bless.Tools.Find; using Bless.Util; using Bless.Gui; using Bless.Gui.Areas; using Bless.Buffers; using Bless.Gui.Dialogs; using System.Text; using Bless.Plugins; using Mono.Unix; namespace Bless.Gui.Plugins { public class FindReplacePlugin : GuiPlugin { DataBook dataBook; FindReplaceWidget widget; Gtk.Action FindAction; Gtk.Action FindNextAction; Gtk.Action FindPreviousAction; Gtk.Action ReplaceAction; IFinder finder; Window mainWindow; UIManager uiManager; const string uiXml = "" + " " + " " + " " + " " + " " + " " + " " + "" + "" + " " + " " + " " + " " + ""; public FindReplacePlugin(Window mw, UIManager uim) { mainWindow = mw; uiManager = uim; name = "FindReplace"; author = "Alexandros Frantzis"; description = "Adds a firefox like find/replace bar"; } public override bool Load() { dataBook = (DataBook)GetDataBook(mainWindow); // create the finder object ProgressDialog findProgressDialog = new ProgressDialog("", mainWindow); finder = new DataBookFinder(dataBook, findProgressDialog.Update); finder.Strategy = new BMFindStrategy(); finder.FirstFind += OnFirstFind; // create the FindReplaceWidget (hidden) widget = new FindReplaceWidget(dataBook, finder); widget.Visible = false; WidgetGroup wgroup = (WidgetGroup)GetWidgetGroup(mainWindow, 0); wgroup.Add(widget); // add the menu items AddActions(uiManager); dataBook.PageAdded += new DataView.DataViewEventHandler(OnDataViewAdded); dataBook.PageRemoved += new DataView.DataViewEventHandler(OnDataViewRemoved); dataBook.SwitchPage += new SwitchPageHandler(OnSwitchPage); loaded = true; return true; } void OnDataViewAdded(DataView dv) { dv.Buffer.Changed += new ByteBuffer.ChangedHandler(OnBufferContentsChanged); dv.BufferChanged += new DataView.DataViewEventHandler(OnBufferChanged); } void OnDataViewRemoved(DataView dv) { dv.Buffer.Changed -= new ByteBuffer.ChangedHandler(OnBufferContentsChanged); dv.BufferChanged -= new DataView.DataViewEventHandler(OnBufferChanged); // if there are no pages left update the menu if (dataBook.NPages == 0) UpdateActions(null); } void OnBufferChanged(DataView dv) { UpdateActions(dv); } void OnBufferContentsChanged(ByteBuffer bb) { Gtk.Application.Invoke(delegate { DataView dv = null; // find DataView that owns bb foreach (DataViewDisplay dvtemp in dataBook.Children) { if (dvtemp.View.Buffer == bb) { dv = dvtemp.View; break; } } UpdateActions(dv); }); } void OnSwitchPage(object o, SwitchPageArgs args) { DataView dv = ((DataViewDisplay)dataBook.GetNthPage((int)args.PageNum)).View; UpdateActions(dv); } private void AddActions(UIManager uim) { ActionEntry[] actionEntries = new ActionEntry[] { new ActionEntry ("FindAction", Stock.Find, null, "F", "Find", new EventHandler(OnFindActivated)), new ActionEntry ("FindNextAction", null, Catalog.GetString("Find _Next"), "F3", null, new EventHandler(OnFindNextActivated)), new ActionEntry ("FindPreviousAction", null, Catalog.GetString("Find _Previous"), "F3", null, new EventHandler(OnFindPreviousActivated)), new ActionEntry ("ReplaceAction", Stock.FindAndReplace, null, "R", "Replace", new EventHandler(OnReplaceActivated)) }; ActionGroup group = new ActionGroup ("SearchActions"); group.Add (actionEntries); uim.InsertActionGroup(group, 0); uim.AddUiFromString(uiXml); FindAction = (Gtk.Action)uim.GetAction("/menubar/Search/Find"); FindNextAction = (Gtk.Action)uim.GetAction("/menubar/Search/FindNext"); FindPreviousAction = (Gtk.Action)uim.GetAction("/menubar/Search/FindPrevious"); ReplaceAction = (Gtk.Action)uim.GetAction("/menubar/Search/Replace"); uim.EnsureUpdate(); } private void OnFindActivated(object o, EventArgs args) { // get pattern from current selection... if (dataBook.NPages > 0) { DataView dv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; widget.LoadWithSelection(dv); } widget.SearchVisible = true; widget.ReplaceVisible = false; widget.Show(); } private void OnReplaceActivated(object o, EventArgs args) { // get pattern from current selection... if (dataBook.NPages > 0) { DataView dv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; widget.LoadWithSelection(dv); } widget.SearchVisible = true; widget.ReplaceVisible = true; widget.Show(); } ///Handle the Search->Find Next command public void OnFindNextActivated(object o, EventArgs args) { finder.FindNext(FindNextAsyncCallback); } void FindNextAsyncCallback(IAsyncResult ar) { ThreadedAsyncResult tar = (ThreadedAsyncResult) ar; FindNextOperation state = (FindNextOperation)tar.AsyncState; if (state.Result == FindNextOperation.OperationResult.Finished && state.Match == null) { InformationAlert ia = new InformationAlert(Catalog.GetString("The pattern you requested was not found."), Catalog.GetString("End of file reached."), mainWindow); ia.Run(); ia.Destroy(); } } ///Handle the Search->Find Previous command public void OnFindPreviousActivated(object o, EventArgs args) { finder.FindPrevious(FindPreviousAsyncCallback); } void FindPreviousAsyncCallback(IAsyncResult ar) { ThreadedAsyncResult tar = (ThreadedAsyncResult) ar; FindPreviousOperation state = (FindPreviousOperation)tar.AsyncState; if (state.Result == FindPreviousOperation.OperationResult.Finished && state.Match == null) { InformationAlert ia = new InformationAlert(Catalog.GetString("The pattern you requested was not found."), Catalog.GetString("Beginning of file reached."), mainWindow); ia.Run(); ia.Destroy(); } } // // called the first time a pattern is sought // void OnFirstFind() { //SearchFindNextAction.Sensitive=true; //SearchFindPreviousAction.Sensitive=true; } void UpdateActions(DataView dv) { if (dv == null) { FindAction.Sensitive = false; FindNextAction.Sensitive = false; FindPreviousAction.Sensitive = false; ReplaceAction.Sensitive = false; return; } FindAction.Sensitive = true; FindNextAction.Sensitive = true; FindPreviousAction.Sensitive = true; ReplaceAction.Sensitive = true; } } /// /// A widget for find and replace operations /// public class FindReplaceWidget : Gtk.HBox { DataBook dataBook; IFinder finder; bool searchPatternChanged; bool replacePatternChanged; byte[] replacePattern; [Gtk.Builder.Object] Gtk.Table FindReplaceTable; [Gtk.Builder.Object] Gtk.Button FindNextButton; [Gtk.Builder.Object] Gtk.Button FindPreviousButton; [Gtk.Builder.Object] Gtk.Button ReplaceButton; [Gtk.Builder.Object] Gtk.Button ReplaceAllButton; [Gtk.Builder.Object] Gtk.Label SearchLabel; [Gtk.Builder.Object] Gtk.Entry SearchPatternEntry; [Gtk.Builder.Object] Gtk.Label SearchAsLabel; [Gtk.Builder.Object] Gtk.ComboBox SearchAsComboBox; [Gtk.Builder.Object] Gtk.Label ReplaceLabel; [Gtk.Builder.Object] Gtk.Entry ReplacePatternEntry; [Gtk.Builder.Object] Gtk.Label ReplaceAsLabel; [Gtk.Builder.Object] Gtk.ComboBox ReplaceAsComboBox; [Gtk.Builder.Object] Gtk.Button CloseButton; Gtk.Widget previouslyFocused; enum ComboIndex { Hexadecimal, Decimal, Octal, Binary, Text } /// /// Whether search-related widgets are visible /// public bool SearchVisible { set { SearchLabel.Visible = value; SearchPatternEntry.Visible = value; SearchAsLabel.Visible = value; SearchAsComboBox.Visible = value; FindNextButton.Visible = value; FindPreviousButton.Visible = value; if (value) SearchPatternEntry.GrabFocus(); } } /// /// Whether replace related widgets are visible /// public bool ReplaceVisible { set { ReplaceLabel.Visible = value; ReplacePatternEntry.Visible = value; ReplaceAsLabel.Visible = value; ReplaceAsComboBox.Visible = value; ReplaceButton.Visible = value; ReplaceAllButton.Visible = value; if (value && SearchPatternEntry.Text.Length > 0) ReplacePatternEntry.GrabFocus(); } } public FindReplaceWidget(DataBook db, IFinder iFinder) { finder = iFinder; dataBook = db; Gtk.Builder builder = new Gtk.Builder(); builder.AddFromFile(FileResourcePath.GetDataPath("ui", "FindReplacePlugin.ui")); builder.Autoconnect(this); this.Shown += OnWidgetShown; SearchPatternEntry.Activated += OnSearchPatternEntryActivated; ReplacePatternEntry.Activated += OnReplacePatternEntryActivated; SearchPatternEntry.FocusGrabbed += OnFocusGrabbed; ReplacePatternEntry.FocusGrabbed += OnFocusGrabbed; SearchAsComboBox.Active = 0; ReplaceAsComboBox.Active = 0; SearchPatternEntry.Completion = new EntryCompletion(); SearchPatternEntry.Completion.Model = new ListStore (typeof (string)); SearchPatternEntry.Completion.TextColumn = 0; ReplacePatternEntry.Completion = new EntryCompletion(); ReplacePatternEntry.Completion.Model = new ListStore (typeof (string)); ReplacePatternEntry.Completion.TextColumn = 0; // initialize replace pattern replacePattern = new byte[0]; this.Add(FindReplaceTable); this.ShowAll(); } /// /// Whether a widget in the FindReplaceWidget has the focus /// bool IsFocusInWidget() { foreach (Gtk.Widget child in FindReplaceTable.Children) { Widget realChild = child; /*if (child.GetType()==typeof(Gtk.Combo)) realChild=(child as Gtk.Combo).Entry; */ if (realChild.HasFocus) return true; } return false; } ///Load the widget with data from the DataView's selection public void LoadWithSelection(DataView dv) { ByteBuffer bb = dv.Buffer; // load selection only if it isn't very large if (this.Sensitive == true && dv.Selection.Size <= 1024 && dv.Selection.Size > 0) { Bless.Util.Range sel = dv.Selection; byte[] ba = new byte[sel.Size]; for (int i = 0;i < sel.Size;i++) { ba[i] = bb[sel.Start+i]; } bool decodingOk = false; Area focusedArea = dv.FocusedArea; if (focusedArea != null) { switch (focusedArea.Type) { case "ascii": string result = Encoding.ASCII.GetString(ba); // if the byte sequence cannot be displayed correctly // as ascii, eg it contains a zero byte, use hexadecimal if (result.IndexOf('\x00') != -1) decodingOk = false; else { SearchAsComboBox.Active = (int)ComboIndex.Text; SearchPatternEntry.Text = result; decodingOk = true; } break; case "decimal": SearchAsComboBox.Active = (int)ComboIndex.Decimal; SearchPatternEntry.Text = ByteArray.ToString(ba, 10); decodingOk = true; break; case "octal": SearchAsComboBox.Active = (int)ComboIndex.Octal; SearchPatternEntry.Text = ByteArray.ToString(ba, 8); decodingOk = true; break; case "binary": SearchAsComboBox.Active = (int)ComboIndex.Binary; SearchPatternEntry.Text = ByteArray.ToString(ba, 2); decodingOk = true; break; }// end switch } if (!decodingOk) { SearchAsComboBox.Active = (int)ComboIndex.Hexadecimal; SearchPatternEntry.Text = ByteArray.ToString(ba, 16); } } } ///Update the search pattern from the text entry void UpdateSearchPattern() { if (!searchPatternChanged) return; try { byte[] ba; switch ((ComboIndex)SearchAsComboBox.Active) { case ComboIndex.Hexadecimal: ba = ByteArray.FromString(SearchPatternEntry.Text, 16); break; case ComboIndex.Decimal: ba = ByteArray.FromString(SearchPatternEntry.Text, 10); break; case ComboIndex.Octal: ba = ByteArray.FromString(SearchPatternEntry.Text, 8); break; case ComboIndex.Binary: ba = ByteArray.FromString(SearchPatternEntry.Text, 2); break; case ComboIndex.Text: ba = Encoding.ASCII.GetBytes(SearchPatternEntry.Text); break; default: ba = new byte[0]; break; } //end switch // if there is something in the text entry but nothing is parsed // it means it is full of spaces if (ba.Length == 0 && SearchPatternEntry.Text.Length != 0) throw new FormatException(Catalog.GetString("Strings representing numbers cannot consist of whitespace characters only.")); else finder.Strategy.Pattern = ba; // append string to drop-down list ListStore ls = (ListStore)SearchPatternEntry.Completion.Model; ls.AppendValues(SearchPatternEntry.Text); } catch (FormatException e) { ErrorAlert ea = new ErrorAlert(Catalog.GetString("Invalid Search Pattern"), e.Message, null); ea.Run(); ea.Destroy(); throw; } searchPatternChanged = false; } void OnSearchPatternEntryActivated(object o, EventArgs args) { if (FindNextButton.Sensitive == true) FindNextButton.Click(); } void OnSearchPatternEntryChanged(object o, EventArgs args) { string pat = SearchPatternEntry.Text; if (pat.Length == 0) { FindNextButton.Sensitive = false; FindPreviousButton.Sensitive = false; ReplaceButton.Sensitive = false; ReplaceAllButton.Sensitive = false; } else { FindNextButton.Sensitive = true; FindPreviousButton.Sensitive = true; ReplaceButton.Sensitive = true; ReplaceAllButton.Sensitive = true; } searchPatternChanged = true; } void OnSearchAsComboBoxChanged(object o, EventArgs args) { searchPatternChanged = true; } void OnFindNextButtonClicked(object o, EventArgs args) { try { UpdateSearchPattern(); this.Sensitive = false; finder.FindNext(FindNextAsyncCallback); } catch (FormatException) { } } void FindNextAsyncCallback(IAsyncResult ar) { ThreadedAsyncResult tar = (ThreadedAsyncResult) ar; FindNextOperation state = (FindNextOperation)tar.AsyncState; if (state.Result == FindNextOperation.OperationResult.Finished && state.Match == null) { InformationAlert ia = new InformationAlert("The pattern you requested was not found.", "End of file reached.", null); ia.Run(); ia.Destroy(); } this.Sensitive = true; this.Visible = false; this.Visible = true; } void OnFindPreviousButtonClicked(object o, EventArgs args) { try { UpdateSearchPattern(); this.Sensitive = false; finder.FindPrevious(FindPreviousAsyncCallback); } catch (FormatException) { } } void FindPreviousAsyncCallback(IAsyncResult ar) { ThreadedAsyncResult tar = (ThreadedAsyncResult) ar; FindPreviousOperation state = (FindPreviousOperation)tar.AsyncState; if (state.Result == FindPreviousOperation.OperationResult.Finished && state.Match == null) { InformationAlert ia = new InformationAlert(Catalog.GetString("The pattern you requested was not found."), Catalog.GetString("Beginning of file reached."), null); ia.Run(); ia.Destroy(); } this.Sensitive = true; this.Visible = false; this.Visible = true; } /// // // Replace related methods // ///Update the replace pattern from the text entry void UpdateReplacePattern() { if (!replacePatternChanged) return; try { switch ((ComboIndex)ReplaceAsComboBox.Active) { case ComboIndex.Hexadecimal: replacePattern = ByteArray.FromString(ReplacePatternEntry.Text, 16); break; case ComboIndex.Decimal: replacePattern = ByteArray.FromString(ReplacePatternEntry.Text, 10); break; case ComboIndex.Octal: replacePattern = ByteArray.FromString(ReplacePatternEntry.Text, 8); break; case ComboIndex.Binary: replacePattern = ByteArray.FromString(ReplacePatternEntry.Text, 2); break; case ComboIndex.Text: replacePattern = Encoding.ASCII.GetBytes(ReplacePatternEntry.Text); break; default: break; } //end switch // if there is something in the text entry but nothing is parsed // it means it is full of spaces if (replacePattern.Length == 0 && ReplacePatternEntry.Text.Length != 0) throw new FormatException("Strings representing numbers cannot consist of only whitespace characters. Leave the text entry completely blank for deletion of matched pattern(s)."); // append string to drop-down list ListStore ls = (ListStore)ReplacePatternEntry.Completion.Model; ls.AppendValues(ReplacePatternEntry.Text); } catch (FormatException e) { ErrorAlert ea = new ErrorAlert("Invalid Replace Pattern", e.Message, null); ea.Run(); ea.Destroy(); throw; } replacePatternChanged = false; } void OnReplacePatternEntryActivated(object o, EventArgs args) { if (ReplaceButton.Sensitive == true) ReplaceButton.Click(); } void OnReplacePatternEntryChanged(object o, EventArgs args) { replacePatternChanged = true; } void OnReplaceAsComboBoxChanged(object o, EventArgs args) { replacePatternChanged = true; } void OnReplaceButtonClicked(object o, EventArgs args) { try { UpdateSearchPattern(); UpdateReplacePattern(); this.Sensitive = false; finder.Replace(replacePattern); finder.FindNext(FindNextAsyncCallback); } catch (FormatException) { } } void OnReplaceAllButtonClicked(object o, EventArgs args) { try { UpdateSearchPattern(); UpdateReplacePattern(); this.Sensitive = false; finder.ReplaceAll(replacePattern, ReplaceAllAsyncCallback); } catch (FormatException) { } } void ReplaceAllAsyncCallback(IAsyncResult ar) { ThreadedAsyncResult tar = (ThreadedAsyncResult) ar; ReplaceAllOperation state = (ReplaceAllOperation)tar.AsyncState; if (state.Result == ReplaceAllOperation.OperationResult.Finished) { InformationAlert ia = new InformationAlert("Found and replaced " + state.NumReplaced + " occurences.", "", null); ia.Run(); ia.Destroy(); } this.Sensitive = true; this.Visible = false; this.Visible = true; } void OnCloseButtonClicked(object o, EventArgs args) { if (dataBook.NPages > 0 && IsFocusInWidget()) { DataViewDisplay curdvd = (DataViewDisplay)dataBook.CurrentPageWidget; curdvd.GrabKeyboardFocus(); } this.Hide(); // forget focus when hiding previouslyFocused = null; } void OnFocusGrabbed(object o, EventArgs args) { // remember which widget has the focus previouslyFocused = (Widget)o; } void OnWidgetShown(object o, EventArgs args) { // when the dialog is shown, select and give the focus // to the previously focused widget if (previouslyFocused != null) previouslyFocused.GrabFocus(); else SearchPatternEntry.GrabFocus(); } protected override bool OnKeyPressEvent(Gdk.EventKey e) { // Escape hides the widget if (e.Key == Gdk.Key.Escape) { CloseButton.Click(); return true; } else return base.OnKeyPressEvent(e); } } } // end namespace bless-0.6.3/src/gui/plugins/GotoOffsetPlugin.cs000066400000000000000000000126321374060072200214560ustar00rootroot00000000000000// created on 6/22/2005 at 12:42 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using Gtk; using Bless.Util; using Bless.Gui.Dialogs; using Bless.Gui; using Bless.Tools.Find; using Bless.Plugins; using Mono.Unix; namespace Bless.Gui.Plugins { public class GotoOffsetPlugin : GuiPlugin { GotoOffsetWidget widget; const string uiXml = "" + " " + " " + " " + " " + ""; Window mainWindow; UIManager uiManager; public GotoOffsetPlugin(Window mw, UIManager uim) { mainWindow = mw; uiManager = uim; name = "GotoOffset"; author = "Alexandros Frantzis"; description = "Adds a firefox like go to offset bar"; loadAfter.Add("FindReplace"); } public override bool Load() { widget = new GotoOffsetWidget((DataBook)GetDataBook(mainWindow)); widget.Visible = false; WidgetGroup wgroup = (WidgetGroup)GetWidgetGroup(mainWindow, 0); wgroup.Add(widget); // add the menu items AddMenuItems(uiManager); loaded = true; return true; } private void AddMenuItems(UIManager uim) { ActionEntry[] actionEntries = new ActionEntry[] { new ActionEntry ("GotoOffsetAction", Stock.JumpTo, Catalog.GetString("_Goto Offset"), "G", null, new EventHandler(OnGotoOffsetActivated)), }; ActionGroup group = new ActionGroup ("GotoActions"); group.Add (actionEntries); uim.InsertActionGroup(group, 0); uim.AddUiFromString(uiXml); uim.EnsureUpdate(); } ///Handle the Search->Find Next command public void OnGotoOffsetActivated(object o, EventArgs args) { widget.Show(); } } /// /// A widget for go to offset operation /// public class GotoOffsetWidget : Gtk.HBox { [Gtk.Builder.Object] Gtk.HBox GotoOffsetHBox; [Gtk.Builder.Object] Gtk.Button GotoOffsetButton; [Gtk.Builder.Object] Gtk.Entry OffsetEntry; [Gtk.Builder.Object] Gtk.Button CloseButton; DataBook dataBook; public GotoOffsetWidget(DataBook db) { dataBook = db; Gtk.Builder builder = new Gtk.Builder(); builder.AddFromFile(FileResourcePath.GetDataPath("ui", "GotoOffsetPlugin.ui")); builder.Autoconnect(this); OffsetEntry.Completion = new EntryCompletion(); OffsetEntry.Completion.Model = new ListStore (typeof (string)); OffsetEntry.Completion.TextColumn = 0; // set button sensitivity OnOffsetEntryChanged(null, null); this.Shown += OnWidgetShown; this.Add(GotoOffsetHBox); this.ShowAll(); } /// /// Whether a widget in the GotoOffsetWidget has the focus /// bool IsFocusInWidget() { foreach (Gtk.Widget child in GotoOffsetHBox.Children) { Widget realChild = child; if (child.GetType() == typeof(Gtk.Alignment)) realChild = (child as Gtk.Alignment).Child; if (realChild.HasFocus) return true; } return false; } void OnOffsetEntryChanged(object o, EventArgs args) { if (OffsetEntry.Text.Length > 0) GotoOffsetButton.Sensitive = true; else GotoOffsetButton.Sensitive = false; } void OnOffsetEntryActivated(object o, EventArgs args) { if (GotoOffsetButton.Sensitive == true) GotoOffsetButton.Click(); } void OnGotoOffsetClicked(object o, EventArgs args) { if (dataBook.NPages == 0) return; DataView dv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; long offset = -1; try { offset = BaseConverter.Parse(OffsetEntry.Text); if (offset >= 0 && offset <= dv.Buffer.Size) { dv.Display.MakeOffsetVisible(offset, DataViewDisplay.ShowType.Closest); dv.MoveCursor(offset, 0); } else { ErrorAlert ea = new ErrorAlert(Catalog.GetString("Invalid Offset"), Catalog.GetString("The offset you specified is outside the file's limits."), null); ea.Run(); ea.Destroy(); } // append string to drop-down list ListStore ls = (ListStore)OffsetEntry.Completion.Model; ls.AppendValues(OffsetEntry.Text); } catch (FormatException e) { ErrorAlert ea = new ErrorAlert(Catalog.GetString("Error in Offset Format"), e.Message, null); ea.Run(); ea.Destroy(); } } void OnWidgetShown(object o, EventArgs args) { OffsetEntry.GrabFocus(); } protected override bool OnKeyPressEvent(Gdk.EventKey e) { if (e.Key == Gdk.Key.Escape) { CloseButton.Click(); return true; } else return base.OnKeyPressEvent(e); } void OnCloseButtonClicked(object o, EventArgs args) { // give focus to active dataview if the widget has it if (dataBook.NPages > 0 && IsFocusInWidget()) { DataViewDisplay curdvd = (DataViewDisplay)dataBook.CurrentPageWidget; curdvd.GrabKeyboardFocus(); } this.Hide(); } } } // namespace bless-0.6.3/src/gui/plugins/HelpOperationsPlugin.cs000066400000000000000000000060401374060072200223270ustar00rootroot00000000000000// created on 10/24/2006 at 12:59 PM /* * Copyright (c) 2006, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using Bless.Gui; using Bless.Plugins; using Bless.Gui.Dialogs; using Bless.Util; using System; using Gtk; using Mono.Unix; namespace Bless.Gui.Plugins { public class HelpOperationsPlugin : GuiPlugin { const string uiXml = "" + " " + " " + " " + " " + " " + ""; //DataBook dataBook; //Window mainWindow; UIManager uiManager; public HelpOperationsPlugin(Window mw, UIManager uim) { //mainWindow = mw; //dataBook = (DataBook)GetDataBook(mainWindow); uiManager = uim; name = "HelpOperations"; author = "Alexandros Frantzis"; description = "Provides access to basic help operations"; } public override bool Load() { AddMenuItems(uiManager); loaded = true; return true; } private void AddMenuItems(UIManager uim) { ActionEntry[] actionEntries = new ActionEntry[] { new ActionEntry ("ContentsAction", Stock.Help, Catalog.GetString("_Contents"), "F1", null, new EventHandler(OnContentsActivated)), new ActionEntry ("AboutAction", null, Catalog.GetString("_About"), null, null, new EventHandler(OnAboutActivated)), }; ActionGroup group = new ActionGroup ("HelpActions"); group.Add (actionEntries); uim.InsertActionGroup(group, 0); uim.AddUiFromString(uiXml); uim.EnsureUpdate(); } ///Handle edit->undo command from menu public void OnContentsActivated(object o, EventArgs args) { #if ENABLE_UNIX_SPECIFIC string helpScript = FileResourcePath.GetDataPath("help_script.sh"); string helpDir = FileResourcePath.GetHelpDir(); System.Diagnostics.Process.Start(helpScript, helpDir); #endif } ///Handle edit->redo command from menu public void OnAboutActivated(object o, EventArgs args) { // if (dataBook.NPages > 0) { // DataView dv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; // dv.Display.Benchmark(); // } Gtk.Dialog aboutDialog = new Bless.Gui.Dialogs.AboutDialog(); aboutDialog.Run(); aboutDialog.Destroy(); } } } //end namespace bless-0.6.3/src/gui/plugins/HistoryPlugin.cs000066400000000000000000000061361374060072200210420ustar00rootroot00000000000000/* * Copyright (c) 2006, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.Text; using Gtk; using Bless.Buffers; using Bless.Plugins; using Bless.Gui; using Bless.Tools; namespace Bless.Gui.Plugins { public class HistoryPlugin : GuiPlugin { UIManager uiManager; uint mergeId; ActionGroup historyActionGroup; public HistoryPlugin(Window mw, UIManager uim) { uiManager = uim; name = "HistoryPlugin"; author = "Alexandros Frantzis"; description = "Provides access to recent files"; loadAfter.Add("FileOperations"); } public override bool Load() { History.Instance.Changed += OnHistoryChanged; historyActionGroup = new ActionGroup ("HistoryActions"); uiManager.InsertActionGroup(historyActionGroup, 0); OnHistoryChanged(History.Instance); loaded = true; return true; } ///Handle additions to history void OnHistoryChanged(History h) { // clear previous list uiManager.RemoveUi(mergeId); uiManager.RemoveActionGroup(historyActionGroup); foreach(Gtk.Action action in historyActionGroup.ListActions()) { historyActionGroup.Remove(action); } StringBuilder sb = new StringBuilder(""); ActionEntry[] actionEntries = new ActionEntry[h.Files.Count]; // add recent files int i = 1; foreach (string file in h.Files) { string actionStr = string.Format("{0}RecentFileAction", i); string menuItemStr = string.Format("_{0}. {1}", i, System.IO.Path.GetFileName(file)); string uiMenuStr = string.Format("", i, actionStr); sb.Append(uiMenuStr); actionEntries[i-1] = new ActionEntry (actionStr, null, menuItemStr, null, null, new EventHandler(OnHistoryMenuItemActivated)); i++; } sb.Append(""); historyActionGroup.Add (actionEntries); uiManager.InsertActionGroup(historyActionGroup, 0); mergeId = uiManager.AddUiFromString(sb.ToString()); uiManager.EnsureUpdate(); } ///Handle Activated event on a HistoryMenuItem void OnHistoryMenuItemActivated(object o, EventArgs args) { Gtk.Action action = (Gtk.Action)o; int i = Convert.ToInt32(action.Name.Substring(0, 1)); string filePath = History.Instance.Files[i-1]; Services.File.LoadFiles(new string[]{filePath}); } } } // end namespace bless-0.6.3/src/gui/plugins/InfobarPlugin.cs000066400000000000000000000347051374060072200207640ustar00rootroot00000000000000// created on 6/10/2005 at 3:15 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using Gtk; using System; using Pango; using Bless.Util; using Bless.Gui; using Bless.Plugins; using Bless.Buffers; using Bless.Tools; using Mono.Unix; namespace Bless.Gui.Plugins { public class InfobarPlugin : GuiPlugin { DataBook dataBook; Infobar widget; Window mainWindow; UIManager uiManager; CheckMenuItem viewStatusbarShowMenuItem; CheckMenuItem viewStatusbarOffsetMenuItem; CheckMenuItem viewStatusbarSelectionMenuItem; CheckMenuItem viewStatusbarOverwriteMenuItem; const string uiXml = "" + " " + " " + " " + " " + " " + " " + " " + " " + " " + ""; public InfobarPlugin(Window mw, UIManager uim) { mainWindow = mw; uiManager = uim; name = "Infobar"; author = "Alexandros Frantzis"; description = "Advanced statusbar"; } public override bool Load() { dataBook = (DataBook)GetDataBook(mainWindow); widget = new Infobar(dataBook); widget.Visible = true; Services.UI.Info = widget; ((VBox)mainWindow.Child).PackEnd(widget, false, false, 0); AddMenuItems(uiManager); dataBook.PageAdded += new DataView.DataViewEventHandler(OnDataViewAdded); dataBook.Removed += new RemovedHandler(OnDataViewRemoved); dataBook.SwitchPage += new SwitchPageHandler(OnSwitchPage); PreferencesChangedHandler handler = new PreferencesChangedHandler(OnPreferencesChanged); Preferences.Proxy.Subscribe("View.Statusbar.Show", "ib1", handler); Preferences.Proxy.Subscribe("View.Statusbar.Selection", "ib1", handler); Preferences.Proxy.Subscribe("View.Statusbar.Overwrite", "ib1", handler); Preferences.Proxy.Subscribe("View.Statusbar.Offset", "ib1", handler); loaded = true; return true; } private void AddMenuItems(UIManager uim) { ToggleActionEntry[] toggleActionEntries = new ToggleActionEntry[] { new ToggleActionEntry ("StatusbarShowAction", null, Catalog.GetString("Show"), null, null, new EventHandler(OnStatusbarShow), false), new ToggleActionEntry ("StatusbarOffsetAction", null, Catalog.GetString("Offset"), null, null, new EventHandler(OnStatusbarOffset), false), new ToggleActionEntry ("StatusbarSelectionAction", null, Catalog.GetString("Selection"), null, null, new EventHandler(OnStatusbarSelection), false), new ToggleActionEntry ("StatusbarOverwriteAction", null, Catalog.GetString("Overwrite"), null, null, new EventHandler(OnStatusbarOverwrite), false) }; ActionEntry[] actionEntries = new ActionEntry[] { new ActionEntry ("Statusbar", null, Catalog.GetString("Statusbar"), null, null, null) }; ActionGroup group = new ActionGroup ("StatusbarActions"); group.Add (toggleActionEntries); group.Add (actionEntries); uim.InsertActionGroup(group, 0); uim.AddUiFromString(uiXml); viewStatusbarShowMenuItem = (CheckMenuItem)uim.GetWidget("/menubar/View/Statusbar/Show"); viewStatusbarOffsetMenuItem = (CheckMenuItem)uim.GetWidget("/menubar/View/Statusbar/Offset"); viewStatusbarSelectionMenuItem = (CheckMenuItem)uim.GetWidget("/menubar/View/Statusbar/Selection"); viewStatusbarOverwriteMenuItem = (CheckMenuItem)uim.GetWidget("/menubar/View/Statusbar/Overwrite"); uim.EnsureUpdate(); } void OnDataViewAdded(DataView dv) { dv.Buffer.Changed += new ByteBuffer.ChangedHandler(OnBufferContentsChanged); dv.BufferChanged += new DataView.DataViewEventHandler(OnBufferChanged); dv.CursorChanged += new DataView.DataViewEventHandler(OnCursorChanged); dv.SelectionChanged += new DataView.DataViewEventHandler(OnSelectionChanged); } void OnDataViewRemoved(object o, RemovedArgs args) { DataView dv = ((DataViewDisplay)args.Widget).View; dv.Buffer.Changed -= new ByteBuffer.ChangedHandler(OnBufferContentsChanged); dv.BufferChanged -= new DataView.DataViewEventHandler(OnBufferChanged); dv.CursorChanged -= new DataView.DataViewEventHandler(OnCursorChanged); dv.SelectionChanged -= new DataView.DataViewEventHandler(OnSelectionChanged); } void OnBufferChanged(DataView dv) { UpdateInfobar(dv); } void OnBufferContentsChanged(ByteBuffer bb) { Gtk.Application.Invoke(delegate { DataView dv = null; // find DataView that owns bb foreach (DataViewDisplay dvtemp in dataBook.Children) { if (dvtemp.View.Buffer == bb) { dv = dvtemp.View; break; } } UpdateInfobar(dv); }); } void OnSwitchPage(object o, SwitchPageArgs args) { DataView dv = ((DataViewDisplay)dataBook.GetNthPage((int)args.PageNum)).View; UpdateInfobar(dv); } void OnCursorChanged(DataView dv) { UpdateInfobar(dv); } void OnSelectionChanged(DataView dv) { UpdateInfobar(dv); } public void OnStatusbarShow(object o, EventArgs args) { Preferences.Proxy.Change("View.Statusbar.Show", viewStatusbarShowMenuItem.Active.ToString(), "ib1"); } ///Handle the View->Statusbar->Offset command public void OnStatusbarOffset(object o, EventArgs args) { Preferences.Proxy.Change("View.Statusbar.Offset", viewStatusbarOffsetMenuItem.Active.ToString(), "ib1"); } ///Handle the View->Statusbar->Selection command public void OnStatusbarSelection(object o, EventArgs args) { Preferences.Proxy.Change("View.Statusbar.Selection", viewStatusbarSelectionMenuItem.Active.ToString(), "ib1"); } ///Handle the View->Statusbar->Overwrite command public void OnStatusbarOverwrite(object o, EventArgs args) { Preferences.Proxy.Change("View.Statusbar.Overwrite", viewStatusbarOverwriteMenuItem.Active.ToString(), "ib1"); } void UpdateInfobar(DataView dv) { if (dataBook.NPages == 0) return; DataView curdv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; if (curdv != dv) return; widget.Update(dv); } void OnPreferencesChanged(Preferences prefs) { if (prefs["View.Statusbar.Show"] == "True") { viewStatusbarShowMenuItem.Active = true; viewStatusbarOffsetMenuItem.Sensitive = true; viewStatusbarSelectionMenuItem.Sensitive = true; viewStatusbarOverwriteMenuItem.Sensitive = true; } else { viewStatusbarShowMenuItem.Active = false; viewStatusbarOffsetMenuItem.Sensitive = false; viewStatusbarSelectionMenuItem.Sensitive = false; viewStatusbarOverwriteMenuItem.Sensitive = false; } if (Preferences.Instance["View.Statusbar.Offset"] == "True") viewStatusbarOffsetMenuItem.Active = true; else viewStatusbarOffsetMenuItem.Active = false; if (Preferences.Instance["View.Statusbar.Selection"] == "True") viewStatusbarSelectionMenuItem.Active = true; else viewStatusbarSelectionMenuItem.Active = false; if (Preferences.Instance["View.Statusbar.Overwrite"] == "True") viewStatusbarOverwriteMenuItem.Active = true; else viewStatusbarOverwriteMenuItem.Active = false; } } /// /// An advanced statusbar for Bless /// public class Infobar : Gtk.HBox, IInfoDisplay { Label MessageLabel; Label OffsetLabel; Label SelectionLabel; Label OverwriteLabel; DataBook dataBook; int numberBase; /// ///Get or set the visibility of the Offset statusbar /// public bool OffsetVisible { get { return OffsetLabel.Visible; } set { OffsetLabel.Visible = value; } } /// ///Get or set the visibility of the Selection statusbar /// public bool SelectionVisible { get { return SelectionLabel.Visible; } set { SelectionLabel.Visible = value; } } /// ///Get or set the visibility of the Overwrite statusbar /// public bool OverwriteVisible { get { return OverwriteLabel.Visible; } set { OverwriteLabel.Visible = value; } } public int NumberBase { set { numberBase = value; if (dataBook.NPages > 0) { DataView curdv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; UpdateOffset(curdv); UpdateSelection(curdv); } } get { return numberBase; } } public Infobar(DataBook db) { dataBook = db; MessageLabel = new Label(); MessageLabel.Ellipsize = Pango.EllipsizeMode.End; MessageLabel.SetAlignment(0.0f, 0.5f); OffsetLabel = new Label(); SelectionLabel = new Label(); OverwriteLabel = new Label(); EventBox OffsetEB = new EventBox(); OffsetEB.Add(OffsetLabel); OffsetEB.ButtonPressEvent += ChangeNumberBase; EventBox SelectionEB = new EventBox(); SelectionEB.Add(SelectionLabel); SelectionEB.ButtonPressEvent += ChangeNumberBase; EventBox OverwriteEB = new EventBox(); OverwriteEB.Add(OverwriteLabel); OverwriteEB.ButtonPressEvent += OnOverwriteLabelPressed; this.PackStart(MessageLabel, true, true, 20); this.PackStart(OffsetEB, false, false, 20); this.PackStart(SelectionEB, false, false, 20); this.PackStart(OverwriteEB, false, false, 20); this.NumberBase = 16; PreferencesChangedHandler handler = new PreferencesChangedHandler(OnPreferencesChanged); Preferences.Proxy.Subscribe("View.Statusbar.Show", "ib2", handler); Preferences.Proxy.Subscribe("View.Statusbar.Selection", "ib2", handler); Preferences.Proxy.Subscribe("View.Statusbar.Overwrite", "ib2", handler); Preferences.Proxy.Subscribe("View.Statusbar.Offset", "ib2", handler); this.ShowAll(); } ///Displays a message in the infobar (for 5 sec) public void DisplayMessage(string message) { MessageLabel.Text = message; GLib.Timeout.Add(5000, ClearStatusMessage); } ///Clears the status bar message (callback) bool ClearStatusMessage() { MessageLabel.Text = ""; return false; } /// /// Updates all the information in the infobar with data from the specified DataView, /// if the specified DataView is active /// public void Update(DataView dv) { UpdateOffset(dv); UpdateSelection(dv); UpdateOverwrite(dv); } /// /// Updates the cursor status bar with data from the specified DataView, /// if the specified DataView is active /// public void UpdateOffset(DataView dv) { if (dataBook.NPages == 0) return; DataView curdv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; if (curdv != dv) return; long coffset = dv.CursorOffset; string coffsetString = BaseConverter.ConvertToString(coffset, numberBase, true, true, 1); string sizeString = BaseConverter.ConvertToString(dv.Buffer.Size - 1, numberBase, true, true, 1); string str = string.Format(Catalog.GetString("Offset: {0} / {1}"), coffsetString, sizeString); OffsetLabel.Text = str; } /// /// Updates the selection status bar with data from the specified DataView, /// if the specified DataView is active /// public void UpdateSelection(DataView dv) { if (dataBook.NPages == 0) return; DataView curdv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; if (curdv != dv) return; Bless.Util.Range sel = dv.Selection; string str; if (sel.IsEmpty() == true) str = Catalog.GetString("Selection: None"); else { string startString = BaseConverter.ConvertToString(sel.Start, numberBase, true, true, 1); string endString = BaseConverter.ConvertToString(sel.End, numberBase, true, true, 1); string sizeString = BaseConverter.ConvertToString(sel.Size, numberBase, true, true, 1); str = string.Format(Catalog.GetString("Selection: {0} to {1}") + " " + Catalog.GetPluralString("({2} byte)", "({2} bytes)", (int)sel.Size), startString, endString, sizeString); } SelectionLabel.Text = str; } /// /// Updates the overwrite status bar with data from the specified DataView, /// if the specified DataView is active /// public void UpdateOverwrite(DataView dv) { if (dataBook.NPages == 0) return; DataView curdv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; if (curdv != dv) return; if (dv.Overwrite == true) OverwriteLabel.Text = Catalog.GetString("OVR"); else OverwriteLabel.Text = Catalog.GetString("INS"); } /// /// Clears the information displayed in the infobar /// public void ClearMessage() { OffsetLabel.Text = Catalog.GetString("Offset: -"); SelectionLabel.Text = Catalog.GetString("Selection: None"); } ///Handle button press on Ins/Ovr statusbar void OnOverwriteLabelPressed (object o, ButtonPressEventArgs args) { if (dataBook.NPages > 0) { Gdk.EventButton e = args.Event; // ignore double and triple-clicks if (e.Type != Gdk.EventType.ButtonPress) return; // set edit mode DataView dv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; dv.Overwrite = !dv.Overwrite; } } void ChangeNumberBase(object o, ButtonPressEventArgs args) { if (dataBook.NPages == 0) return; Gdk.EventButton e = args.Event; // ignore double and triple-clicks if (e.Type != Gdk.EventType.ButtonPress) return; // cycle 8, 10 and 16 number bases if (this.NumberBase == 8) this.NumberBase = 10; else if (this.NumberBase == 10) this.NumberBase = 16; else if (this.NumberBase == 16) this.NumberBase = 8; } void OnPreferencesChanged(Preferences prefs) { if (prefs["View.Statusbar.Show"] == "True") this.Visible = true; else this.Visible = false; if (Preferences.Instance["View.Statusbar.Offset"] == "True") this.OffsetVisible = true; else this.OffsetVisible = false; if (Preferences.Instance["View.Statusbar.Selection"] == "True") this.SelectionVisible = true; else this.SelectionVisible = false; if (Preferences.Instance["View.Statusbar.Overwrite"] == "True") this.OverwriteVisible = true; else this.OverwriteVisible = false; } } } // end namespace bless-0.6.3/src/gui/plugins/PatternMatchHighlightPlugin.cs000066400000000000000000000123511374060072200236170ustar00rootroot00000000000000// created on 20/3/2008 at 9:02 PM /* * Copyright (c) 2008, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using Gtk; using Bless.Util; using Bless.Tools.Find; using Bless.Tools; using Bless.Gui; using Bless.Buffers; using Bless.Plugins; using Bless.Gui.Areas; using Bless.Gui.Drawers; namespace Bless.Gui.Plugins { public class PatternMatchHighlightPlugin : GuiPlugin { DataBook dataBook; PatternHighlighter patternHighlighter; Window mainWindow; IPluginPreferences pluginPreferences; public PatternMatchHighlightPlugin(Window mw, UIManager uim) { mainWindow = mw; pluginPreferences = new PatternMatchPreferences(); name = "PatternMatchHighlight"; author = "Alexandros Frantzis"; description = "Highlights all matches of the current selection"; } public override bool Load() { dataBook = (DataBook)GetDataBook(mainWindow); patternHighlighter = new PatternHighlighter(dataBook); Preferences.Proxy.Subscribe("Highlight.PatternMatch", "ph", new PreferencesChangedHandler(OnPreferencesChanged)); loaded = true; return true; } public override IPluginPreferences PluginPreferences { get { return pluginPreferences; } } void OnPreferencesChanged(Preferences prefs) { if (prefs["Highlight.PatternMatch"] == "True") patternHighlighter.Active = true; else patternHighlighter.Active = false; } } class PatternHighlighter { DataBook dataBook; bool active; IFindStrategy findStrategy; public bool Active { get { return active; } set { active = value; if (dataBook.NPages > 0) { DataViewDisplay dvd = (DataViewDisplay)dataBook.CurrentPageWidget; dvd.Redraw(); } } } public PatternHighlighter(DataBook db) { dataBook = db; findStrategy = new BMFindStrategy(); foreach(DataViewDisplay dvd in dataBook.Children) { OnDataViewAdded(dvd.View); } dataBook.PageAdded += new DataView.DataViewEventHandler(OnDataViewAdded); dataBook.Removed += new RemovedHandler(OnDataViewRemoved); } void OnDataViewAdded(DataView dv) { dv.Display.Layout.AreaGroup.PreRenderEvent += new AreaGroup.PreRenderHandler(BeforeRender); } void OnDataViewRemoved(object o, RemovedArgs args) { DataViewDisplay dvd = (DataViewDisplay)args.Widget; dvd.Layout.AreaGroup.PreRenderEvent -= new AreaGroup.PreRenderHandler(BeforeRender); } /// /// Adds pattern match highlights to an area group before it is rendered /// void BeforeRender(AreaGroup ag) { if (!active) return; Util.Range sel = ag.Selection; if (sel.IsEmpty() || sel.Size > 512) return; int nrows; Util.Range view = ag.GetViewRange(out nrows); findStrategy.Buffer = ag.Buffer; findStrategy.Position = view.Start; findStrategy.Pattern = ag.Buffer.RangeToByteArray(sel); // Merge overlapping matches Util.Range match; Util.Range currentHighlight = new Util.Range(); while ((match = findStrategy.FindNext(view.End)) != null) { if (currentHighlight.End >= match.Start) currentHighlight.End = match.End; else { ag.AddHighlight(currentHighlight.Start, currentHighlight.End, Drawer.HighlightType.PatternMatch); currentHighlight = match; } } ag.AddHighlight(currentHighlight.Start, currentHighlight.End, Drawer.HighlightType.PatternMatch); } } class PatternMatchPreferences : IPluginPreferences { PreferencesWidget preferencesWidget; public Widget Widget { get { if (preferencesWidget == null) InitWidget(); return preferencesWidget; } } public void LoadPreferences() { if (preferencesWidget == null) InitWidget(); if (Preferences.Instance["Highlight.PatternMatch"] == "True") preferencesWidget.EnableHighlightCheckButton.Active = true; else preferencesWidget.EnableHighlightCheckButton.Active = false; } public void SavePreferences() { } void InitWidget() { preferencesWidget = new PreferencesWidget(); preferencesWidget.EnableHighlightCheckButton.Toggled += OnEnableHighlightToggled; } void OnEnableHighlightToggled(object o, EventArgs args) { Preferences.Instance["Highlight.PatternMatch"] = preferencesWidget.EnableHighlightCheckButton.Active.ToString(); } } class PreferencesWidget : Gtk.HBox { Gtk.CheckButton enableHighlightCheckButton; public Gtk.CheckButton EnableHighlightCheckButton { get { return enableHighlightCheckButton; } } public PreferencesWidget() { enableHighlightCheckButton = new Gtk.CheckButton("Highlight matches of selection pattern"); this.PackStart(enableHighlightCheckButton, false, false, 6); this.ShowAll(); } } } // end namespace bless-0.6.3/src/gui/plugins/ProgressDisplayPlugin.cs000066400000000000000000000067361374060072200225410ustar00rootroot00000000000000// created on 4/5/2007 at 2:06 PM /* * Copyright (c) 2007, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using Gtk; using System; using Bless.Util; using Bless.Gui; using Bless.Plugins; using Bless.Buffers; using Mono.Unix; namespace Bless.Gui.Plugins { /// /// Plugin to display progress of various events in a uniform way /// public class ProgressDisplayPlugin : GuiPlugin { ProgressDisplayWidget widget; Window mainWindow; public ProgressDisplayPlugin(Window mw, UIManager uim) { mainWindow = mw; name = "ProgressDisplay"; author = "Alexandros Frantzis"; description = "Progress Display Bar"; loadAfter.Add("Infobar"); } public override bool Load() { widget = new ProgressDisplayWidget(); widget.Visible = true; // register the service Services.UI.Progress = widget; ((VBox)mainWindow.Child).PackEnd(widget, false, false, 0); loaded = true; return true; } } /// /// Widget that displays a series of progress bars /// public class ProgressDisplayWidget : Gtk.VBox, IProgressDisplay { public ProgressDisplayWidget() { } /// /// Get a callback for a new progress bar /// public ProgressCallback NewCallback() { ProgressDisplayBar pdb = new ProgressDisplayBar(); this.PackStart(pdb); pdb.DestroyEvent += OnProgressDisplayBarDestroyed; return pdb.Update; } void OnProgressDisplayBarDestroyed (object o, DestroyEventArgs args) { ProgressDisplayBar pdb = (ProgressDisplayBar)o; pdb.DestroyEvent -= OnProgressDisplayBarDestroyed; this.Remove(pdb); } } public class ProgressDisplayBar : Gtk.HBox { [Gtk.Builder.Object] Gtk.HBox ProgressBarHBox; [Gtk.Builder.Object] Gtk.Button CancelButton; [Gtk.Builder.Object] Gtk.ProgressBar ProgressBar; bool cancelClicked; public ProgressDisplayBar() { Gtk.Builder builder = new Gtk.Builder(); builder.AddFromFile(FileResourcePath.GetDataPath("ui", "ProgressDisplayPlugin.ui")); builder.Autoconnect(this); this.Add(ProgressBarHBox); this.Hide(); } /// /// Handles the various progress actions /// public bool Update(object o, ProgressAction action) { if (action == ProgressAction.Hide) { this.Visible = false; return false; } else if (action == ProgressAction.Show) { this.Visible = true; return false; } else if (action == ProgressAction.Message) { ProgressBar.Text = (string)o; return false; } else if (action == ProgressAction.Destroy) { this.Destroy(); return false; } ProgressBar.Fraction = (double)o; if (cancelClicked == true) { cancelClicked = false; return true; } else return false; } public void OnCancelButtonClicked(object o, EventArgs args) { cancelClicked = true; } } } // end namespace bless-0.6.3/src/gui/plugins/SelectLayoutPlugin.cs000066400000000000000000000045651374060072200220220ustar00rootroot00000000000000// created on 10/24/2006 at 12:59 PM /* * Copyright (c) 2006, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using Bless.Buffers; using Bless.Gui; using Bless.Plugins; using Bless.Gui.Dialogs; using Bless.Tools; using System; using System.IO; using Gtk; using Mono.Unix; namespace Bless.Gui.Plugins { public class SelectLayoutPlugin : GuiPlugin { const string uiXml = "" + " " + " " + " " + " " + ""; DataBook dataBook; Window mainWindow; UIManager uiManager; public SelectLayoutPlugin(Window mw, UIManager uim) { mainWindow = mw; uiManager = uim; name = "SelectLayout"; author = "Alexandros Frantzis"; description = "Change the layout of a view"; } public override bool Load() { dataBook = (DataBook)GetDataBook(mainWindow); AddMenuItems(uiManager); loaded = true; return true; } private void AddMenuItems(UIManager uim) { ActionEntry[] actionEntries = new ActionEntry[] { new ActionEntry ("LayoutsAction", null, Catalog.GetString("_Layouts..."), "L", null, new EventHandler(OnLayoutsActivated)), }; ActionGroup group = new ActionGroup ("SelectLayoutActions"); group.Add (actionEntries); uim.InsertActionGroup(group, 0); uim.AddUiFromString(uiXml); uim.EnsureUpdate(); } ///Handle view->layouts command from menu public void OnLayoutsActivated(object o, EventArgs args) { LayoutSelectionDialog lsd = new LayoutSelectionDialog(dataBook); lsd.Show(); } } } //end namespace bless-0.6.3/src/gui/plugins/SelectRangePlugin.cs000066400000000000000000000166141374060072200215770ustar00rootroot00000000000000/* * Copyright (c) 2006, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using Gtk; using Bless.Buffers; using Bless.Util; using Bless.Gui.Dialogs; using Bless.Gui; using Bless.Plugins; using Mono.Unix; namespace Bless.Gui.Plugins { public class SelectRangePlugin : GuiPlugin { SelectRangeWidget widget; const string uiXml = "" + " " + " " + " " + " " + " " + " " + " " + ""; Window mainWindow; UIManager uiManager; DataBook dataBook; public SelectRangePlugin(Window mw, UIManager uim) { mainWindow = mw; uiManager = uim; name = "SelectRange"; author = "Alexandros Frantzis"; description = "Adds a select range bar"; loadAfter.Add("EditOperations"); } public override bool Load() { dataBook = (DataBook)GetDataBook(mainWindow); widget = new SelectRangeWidget(dataBook); widget.Visible = false; WidgetGroup wgroup = (WidgetGroup)GetWidgetGroup(mainWindow, 0); wgroup.Add(widget); AddMenuItems(uiManager); loaded = true; return true; } private void AddMenuItems(UIManager uim) { ActionEntry[] actionEntries = new ActionEntry[] { new ActionEntry ("SelectAllAction", null, Catalog.GetString("Select _All"), "A", null, new EventHandler(OnSelectAllActivated)), new ActionEntry ("SelectRangeAction", Stock.JumpTo, Catalog.GetString("_Select Range"), "R", null, new EventHandler(OnSelectRangeActivated)), }; ActionGroup group = new ActionGroup ("SelectRangeActions"); group.Add (actionEntries); uim.InsertActionGroup(group, 0); uim.AddUiFromString(uiXml); uim.EnsureUpdate(); } ///Handle the Edit->Select All command public void OnSelectAllActivated(object o, EventArgs args) { if (dataBook.NPages == 0) return; DataView dv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; dv.Selection = dv.Buffer.Range; } ///Handle the Edit->Select Range command public void OnSelectRangeActivated(object o, EventArgs args) { if (dataBook.NPages > 0) { DataView dv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; widget.LoadWithSelection(dv); } widget.Show(); } } /// /// A widget for the select range operation /// public class SelectRangeWidget : Gtk.HBox { [Gtk.Builder.Object] Gtk.HBox SelectRangeHBox; [Gtk.Builder.Object] Gtk.Button SelectButton; [Gtk.Builder.Object] Gtk.Entry FromEntry; [Gtk.Builder.Object] Gtk.Entry ToEntry; [Gtk.Builder.Object] Gtk.Button CloseButton; DataBook dataBook; public SelectRangeWidget(DataBook db) { dataBook = db; Gtk.Builder builder = new Gtk.Builder(); builder.AddFromFile(FileResourcePath.GetDataPath("ui", "SelectRangePlugin.ui")); builder.Autoconnect(this); // set up entry completions FromEntry.Completion = new EntryCompletion(); FromEntry.Completion.Model = new ListStore (typeof (string)); FromEntry.Completion.TextColumn = 0; ToEntry.Completion = new EntryCompletion(); ToEntry.Completion.Model = new ListStore (typeof (string)); ToEntry.Completion.TextColumn = 0; // set button sensitivity OnEntryChanged(null, null); this.Shown += OnWidgetShown; this.Add(SelectRangeHBox); this.ShowAll(); } ///Load the widget with data from the DataView's selection public void LoadWithSelection(DataView dv) { // load selection only if it isn't very large if (dv.Selection.Size > 0) { Bless.Util.Range sel = dv.Selection; FromEntry.Text = sel.Start.ToString(); ToEntry.Text = sel.End.ToString(); } else { FromEntry.Text = dv.CursorOffset.ToString(); } FromEntry.GrabFocus(); } /// /// Whether a widget in the SelectRangeWidget has the focus /// bool IsFocusInWidget() { foreach (Gtk.Widget child in SelectRangeHBox.Children) { Widget realChild = child; if (child.GetType() == typeof(Gtk.Alignment)) realChild = (child as Gtk.Alignment).Child; if (realChild.HasFocus) return true; } return false; } void OnEntryChanged(object o, EventArgs args) { if (ToEntry.Text.Length > 0 && FromEntry.Text.Length > 0) SelectButton.Sensitive = true; else SelectButton.Sensitive = false; } void OnEntryActivated(object o, EventArgs args) { if (SelectButton.Sensitive == true) SelectButton.Click(); } void OnSelectButtonClicked(object o, EventArgs args) { if (dataBook.NPages == 0) return; DataView dv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; long fromOffset = -1; long toOffset = -1; int relative = 0; try { fromOffset = BaseConverter.Parse(FromEntry.Text); } catch (FormatException e) { ErrorAlert ea = new ErrorAlert(Catalog.GetString("Error in From Offset Format"), e.Message, null); ea.Run(); ea.Destroy(); return; } string toString = ToEntry.Text.Trim(); if (toString.StartsWith("+")) relative = 1; else if (toString.StartsWith("-")) relative = -1; toString = toString.TrimStart(new char[]{'+', '-'}); try { toOffset = BaseConverter.Parse(toString); } catch (FormatException e) { ErrorAlert ea = new ErrorAlert(Catalog.GetString("Error in To Offset Format"), e.Message, null); ea.Run(); ea.Destroy(); return; } if (relative != 0) toOffset = fromOffset + relative * (toOffset - 1); if (toOffset >= 0 && toOffset < dv.Buffer.Size && fromOffset >= 0 && fromOffset < dv.Buffer.Size) { dv.SetSelection(fromOffset, toOffset); dv.Display.MakeOffsetVisible(toOffset, DataViewDisplay.ShowType.Closest); // append string to drop-down lists ListStore ls = (ListStore)ToEntry.Completion.Model; ls.AppendValues(ToEntry.Text); ls = (ListStore)FromEntry.Completion.Model; ls.AppendValues(FromEntry.Text); } else { ErrorAlert ea = new ErrorAlert(Catalog.GetString("Invalid Range"), Catalog.GetString("The range you specified is outside the file's limits."), null); ea.Run(); ea.Destroy(); } } void OnWidgetShown(object o, EventArgs args) { FromEntry.GrabFocus(); } protected override bool OnKeyPressEvent(Gdk.EventKey e) { if (e.Key == Gdk.Key.Escape) { CloseButton.Click(); return true; } else return base.OnKeyPressEvent(e); } void OnCloseButtonClicked(object o, EventArgs args) { // give focus to active dataview if the widget has it if (dataBook.NPages > 0 && IsFocusInWidget()) { DataViewDisplay curdvd = (DataViewDisplay)dataBook.CurrentPageWidget; curdvd.GrabKeyboardFocus(); } this.Hide(); } } } // namespace bless-0.6.3/src/gui/plugins/StatisticsPlugin.cs000066400000000000000000000241211374060072200215250ustar00rootroot00000000000000// created on 20/25/2006 at 3:24 PM /* * Copyright (c) 2006, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.Collections; using Cairo; using Gtk; using Bless.Tools; using Bless.Util; using Bless.Gui; using Bless.Gui.Dialogs; using Bless.Buffers; using Bless.Plugins; namespace Bless.Gui.Plugins { public class StatisticsPlugin : GuiPlugin { DataBook dataBook; Window mainWindow; ToggleAction statisticsAction; UIManager uiManager; StatisticsWidget sw; const string uiXml = "" + " " + " " + " " + ""; public StatisticsPlugin(Window mw, UIManager uim) { mainWindow = mw; uiManager = uim; name = "File Statistics"; author = "Alexandros Frantzis"; description = "File statistics"; } public override bool Load() { dataBook = (DataBook)GetDataBook(mainWindow); WidgetGroup wg = (WidgetGroup)GetWidgetGroup(mainWindow, 1); sw = new StatisticsWidget(dataBook); wg.Add(sw); AddMenuItems(uiManager); Preferences.Proxy.Subscribe("Tools.Statistics.Show", "stats1", new PreferencesChangedHandler(OnPreferencesChanged)); loaded = true; return true; } private void AddMenuItems(UIManager uim) { ToggleActionEntry[] toggleActionEntries = new ToggleActionEntry[] { new ToggleActionEntry ("StatisticsAction", null, "File Statistics", null, null, new EventHandler(OnToolsStatisticsActivated), false), }; ActionGroup group = new ActionGroup ("StatisticsActions"); group.Add (toggleActionEntries); uim.InsertActionGroup(group, 0); uim.AddUiFromString(uiXml); statisticsAction = (ToggleAction)uim.GetAction("/menubar/Tools/Statistics"); uim.EnsureUpdate(); } ///Handle the View->Conversion Table command public void OnToolsStatisticsActivated(object o, EventArgs args) { Preferences.Proxy.Change("Tools.Statistics.Show", statisticsAction.Active.ToString(), "stats1"); } void OnPreferencesChanged(Preferences prefs) { Console.WriteLine("Prefs changed stat1"); if (prefs["Tools.Statistics.Show"] == "True") statisticsAction.Active = true; else statisticsAction.Active = false; } } public class StatisticsInfo { public int[] Freqs; public bool Changed; public StatisticsInfo() { Freqs = new int[256]; Changed = true; } } public class StatisticsWidget : Gtk.HBox { StatisticsDrawWidget sdw; DataBook dataBook; Hashtable info; public StatisticsWidget(DataBook db) { info = new Hashtable(); dataBook = db; dataBook.SwitchPage += new SwitchPageHandler(OnSwitchPage); dataBook.PageAdded += new DataView.DataViewEventHandler(OnDataViewAdded); dataBook.Removed += new RemovedHandler(OnDataViewRemoved); foreach(DataViewDisplay dvd in dataBook.Children) { dvd.View.Buffer.Changed += new ByteBuffer.ChangedHandler(OnBufferContentsChanged); dvd.View.BufferChanged += new DataView.DataViewEventHandler(OnBufferChanged); info[dvd.View] = new StatisticsInfo(); } sdw = new StatisticsDrawWidget(); Preferences.Proxy.Subscribe("Tools.Statistics.Show", "stats2", new PreferencesChangedHandler(OnPreferencesChanged)); this.Add(sdw); this.ShowAll(); } void OnDialogResponse(object o, Gtk.ResponseArgs args) { dataBook.SwitchPage -= new SwitchPageHandler(OnSwitchPage); dataBook.PageAdded -= new DataView.DataViewEventHandler(OnDataViewAdded); dataBook.Removed -= new RemovedHandler(OnDataViewRemoved); foreach(DataViewDisplay dvd in dataBook.Children) { dvd.View.Buffer.Changed -= new ByteBuffer.ChangedHandler(OnBufferContentsChanged); dvd.View.BufferChanged -= new DataView.DataViewEventHandler(OnBufferChanged); } this.Destroy(); } void OnDataViewAdded(DataView dv) { dv.Buffer.Changed += new ByteBuffer.ChangedHandler(OnBufferContentsChanged); dv.BufferChanged += new DataView.DataViewEventHandler(OnBufferChanged); info[dv] = new StatisticsInfo(); } void OnDataViewRemoved(object o, RemovedArgs args) { DataView dv = ((DataViewDisplay)args.Widget).View; dv.Buffer.Changed -= new ByteBuffer.ChangedHandler(OnBufferContentsChanged); dv.BufferChanged -= new DataView.DataViewEventHandler(OnBufferChanged); info.Remove(dv); } void OnBufferChanged(DataView dv) { if (info.Contains(dv)) (info[dv] as StatisticsInfo).Changed = true; else { StatisticsInfo si = new StatisticsInfo(); info[dv] = si; } UpdateStatistics(dv); } void OnBufferContentsChanged(ByteBuffer bb) { DataView dv = null; // find DataView that owns bb foreach (DataViewDisplay dvtemp in dataBook.Children) { if (dvtemp.View.Buffer == bb) { dv = dvtemp.View; break; } } if (dv == null) return; OnBufferChanged(dv); } void OnSwitchPage(object o, SwitchPageArgs args) { DataView dv = ((DataViewDisplay)dataBook.GetNthPage((int)args.PageNum)).View; if (dv == null) return; if (!info.Contains(dv)) info[dv] = new StatisticsInfo(); UpdateStatistics(dv); } void UpdateStatistics(DataView dv) { DataView curdv = ((DataViewDisplay)dataBook.CurrentPageWidget).View; if (curdv != dv) return; StatisticsInfo si = (info[dv] as StatisticsInfo); if (si.Changed == true) { ByteBuffer bb = dv.Buffer; for (int i = 0;i < si.Freqs.Length;i++) { si.Freqs[i] = 0; } for (int i = 0;i < bb.Size;i++) { ++si.Freqs[bb[i]]; } si.Changed = false; } sdw.Update(si.Freqs); } protected override void OnHidden() { Console.WriteLine("Stats Hide"); Preferences.Proxy.Change("Tools.Statistics.Show", "False", "stats2"); base.OnHidden(); } protected override void OnShown() { Preferences.Proxy.Change("Tools.Statistics.Show", "True", "stats2"); base.OnShown(); } void OnPreferencesChanged(Preferences prefs) { Console.WriteLine("Prefch STats2"); if (prefs["Tools.Statistics.Show"] == "True") this.Visible = true; else this.Visible = false; } } /// A widget to convert the data at the current offset to various types public class StatisticsDrawWidget: Gtk.DrawingArea { int[] freqs; int[] dummyFreqs; PointD[] barStart; PointD[] barEnd; double freqWidth; int previousHighlight; int currentHighlight; void DrawBar(Cairo.Context gr, int b) { gr.MoveTo(barStart[b]); gr.LineTo (barEnd[b]); gr.Stroke(); } void UpdateHighlight() { Gdk.Window win = this.GdkWindow; Cairo.Context g = Gdk.CairoHelper.Create(win); int x, y, w, h, d; win.GetGeometry(out x, out y, out w, out h, out d); g.Scale (w, h); g.LineWidth = (1.0 / freqs.Length) * 0.6; if (previousHighlight != -1) { /*int start=previousHighlight-1; int end=previousHighlight+1; if (start<0) start=0; if (end>=barStart.Length) end=barStart.Length-1;*/ g.Color = new Color(0.0, 0.0, 0.0); //for(int i=start; i<=end; i++) DrawBar(g, previousHighlight); } if (currentHighlight != -1) { g.Color = new Color(1.0, 0.0, 0.0); DrawBar(g, currentHighlight); } } void Draw (Cairo.Context gr, int width, int height) { gr.Scale (width, height); gr.Color = new Color(1.0, 1.0, 1.0); gr.Rectangle(0.0, 0.0, 1.0, 1.0); gr.Stroke(); gr.Color = new Color(0.0, 0.0, 0.0); gr.LineWidth = (1.0 / freqs.Length) * 0.6; for (int i = 0; i < freqs.Length; i++) { if (previousHighlight == i) gr.Color = new Color(1.0, 0.0, 0.0); DrawBar(gr, i); if (previousHighlight == i) gr.Color = new Color(0.0, 0.0, 0.0); } } public StatisticsDrawWidget() { dummyFreqs = new int[0]; barStart = new PointD[0]; barEnd = new PointD[0]; freqs = dummyFreqs; this.AddEvents((int)Gdk.EventMask.PointerMotionMask); this.AddEvents((int)Gdk.EventMask.PointerMotionHintMask); this.MotionNotifyEvent += OnMotionNotify; previousHighlight = -1; currentHighlight = -1; } protected override bool OnExposeEvent (Gdk.EventExpose args) { Gdk.Window win = args.Window; Cairo.Context g = Gdk.CairoHelper.Create(win); int x, y, w, h, d; win.GetGeometry(out x, out y, out w, out h, out d); this.HeightRequest = w / 5; Draw (g, w, h); return true; } ///Update all conversion entries public void Update(int[] freqs) { if (freqs == null) this.freqs = dummyFreqs; else { this.freqs = freqs; if (freqs.Length != barStart.Length) { barStart = new PointD[freqs.Length]; barEnd = new PointD[freqs.Length]; } } DoDrawingCalculations(); previousHighlight = -1; currentHighlight = -1; this.QueueDraw(); } void DoDrawingCalculations() { freqWidth = (1.0 / freqs.Length); int max = 0; for (int i = 0; i < freqs.Length; i++) { if (freqs[i] > max) max = freqs[i]; } for (int i = 0; i < barStart.Length; i++) { barStart[i].X = i * freqWidth; barStart[i].Y = 1.0; barEnd[i].X = barStart[i].X; barEnd[i].Y = 1.0 - ((double)freqs[i]) / max; } } void OnMotionNotify(object o, MotionNotifyEventArgs args) { Gdk.EventMotion e = args.Event; int x, y; Gdk.ModifierType state; if (e.IsHint) this.GdkWindow.GetPointer(out x, out y, out state); else { x = (int)e.X; y = (int)e.Y; state = e.State; } Gdk.Rectangle alloc = this.Allocation; //Console.WriteLine("x {0} freq {1} width{2}", x, freqWidth, alloc.Width); currentHighlight = (int)((x / (freqWidth * alloc.Width))) + 1; Console.WriteLine(currentHighlight); if (previousHighlight != currentHighlight) { UpdateHighlight(); previousHighlight = currentHighlight; } } } } // end namespace bless-0.6.3/src/meson.build000066400000000000000000000202421374060072200155620ustar00rootroot00000000000000src_build_dir = meson.current_build_dir() # Used by tests assembly_install_dir = join_paths(get_option('libdir'), meson.project_name()) conf_data = configuration_data() conf_data.set('PACKAGE', meson.project_name()) conf_data.set('VERSION', meson.project_version()) conf_data.set('GETTEXT_PACKAGE', meson.project_name()) conf_data.set('datadir', join_paths(get_option('prefix'), get_option('datadir'))) conf_data.set('blessassemblydir', join_paths(get_option('prefix'), assembly_install_dir)) configure_defines_cs = configure_file( input: 'util/ConfigureDefines.cs.tmpl.in', output: 'ConfigureDefines.cs', configuration: conf_data ) bless_bin = configure_file( input: 'bless-bin.in', output: 'bless', configuration: conf_data, install_dir: join_paths(get_option('prefix'), get_option('bindir')), ) util_lib = library( 'Bless.Util', files( 'util/BaseConverter.cs', 'util/ByteArray.cs', 'util/Deque.cs', 'util/FileResourcePath.cs', 'util/IntervalTree.cs', 'util/List.cs', 'util/Portable.cs', 'util/ProgressCallback.cs', 'util/RangeCollection.cs', 'util/Range.cs', 'util/RedBlackTree.cs', 'util/TempFile.cs', 'util/ThreadedAsyncOperation.cs' ) + [configure_defines_cs], dependencies: glib_sharp_2_dep, cs_args: '-r:Mono.Posix', install: true, install_dir: assembly_install_dir, ) tools_lib = library( 'Bless.Tools', files( 'tools/History.cs', 'tools/Preferences.cs', 'tools/Session.cs', ), install: true, install_dir: assembly_install_dir, ) buffers_lib = library( 'Bless.Buffers', files( 'buffers/ByteBuffer.cs', 'buffers/ByteBufferAction.cs', 'buffers/FileBuffer.cs', 'buffers/IBuffer.cs', 'buffers/ISaveState.cs', 'buffers/SaveAsOperation.cs', 'buffers/SaveInPlaceOperation.cs', 'buffers/SaveOperation.cs', 'buffers/Segment.cs', 'buffers/SegmentCollection.cs', 'buffers/SimpleBuffer.cs' ), dependencies: gtk_sharp_2_dep, cs_args: '-r:Mono.Posix', link_with: [ tools_lib, util_lib ], install: true, install_dir: assembly_install_dir, ) tools_export_lib = library( 'Bless.Tools.Export', files( 'tools/export/ExporterOperation.cs', 'tools/export/IExportBuilder.cs', 'tools/export/IExporter.cs', 'tools/export/InterpretedPatternExporter.cs', 'tools/export/IPatternExporter.cs', ), cs_args: '-r:Mono.Posix', link_with: [ buffers_lib, util_lib ], install: true, install_dir: assembly_install_dir, ) tools_find_lib = library( 'Bless.Tools.Find', files( 'tools/find/BMFindStrategy.cs', 'tools/find/FindAsyncResult.cs', 'tools/find/FindOperations.cs', 'tools/find/IFinder.cs', 'tools/find/IFindStrategy.cs', ), link_with: [ buffers_lib, util_lib ], install: true, install_dir: assembly_install_dir, ) gui_drawers_lib = library( 'Bless.Gui.Drawers', files( 'gui/drawers/AsciiDrawer.cs', 'gui/drawers/BinaryDrawer.cs', 'gui/drawers/DecimalDrawer.cs', 'gui/drawers/Drawer.cs', 'gui/drawers/HexDrawer.cs', 'gui/drawers/OctalDrawer.cs', 'gui/drawers/PixmapManager.cs', ), dependencies: gtk_sharp_2_dep, install: true, install_dir: assembly_install_dir, ) gui_areas_lib = library( 'Bless.Gui.Areas', files( 'gui/areas/Area.cs', 'gui/areas/AreaGroup.cs', 'gui/areas/Highlight.cs', ), dependencies: gtk_sharp_2_dep, link_with: [ buffers_lib, gui_drawers_lib, tools_find_lib, util_lib ], install: true, install_dir: assembly_install_dir, ) plugins_lib = library( 'Bless.Plugins', files( 'plugins/AreaPlugin.cs', 'plugins/ExportPlugin.cs', 'plugins/GuiPlugin.cs', 'plugins/IPluginPreferences.cs', 'plugins/Plugin.cs', 'plugins/PluginManager.cs', ), dependencies: gtk_sharp_2_dep, link_with: [ gui_areas_lib, tools_export_lib, util_lib ], install: true, install_dir: assembly_install_dir, ) gui_lib = library( 'Bless.Gui', files( 'gui/DataBook.cs', 'gui/DataBookFinder.cs', 'gui/DataViewControl.cs', 'gui/DataView.cs', 'gui/DataViewDisplay.cs', 'gui/dialogs/AboutDialog.cs', 'gui/dialogs/Alert.cs', 'gui/dialogs/ErrorAlert.cs', 'gui/dialogs/ExportDialog.cs', 'gui/dialogs/FileOverwriteAlert.cs', 'gui/dialogs/InformationAlert.cs', 'gui/dialogs/LayoutSelectionDialog.cs', 'gui/dialogs/PreferencesDialog.cs', 'gui/dialogs/ProgressDialog.cs', 'gui/dialogs/RevertConfirmationAlert.cs', 'gui/dialogs/SaveConfirmationAlert.cs', 'gui/dialogs/SaveConfirmationMultiAlert.cs', 'gui/dialogs/WarningAlert.cs', 'gui/FileChangedBar.cs', 'gui/FileService.cs', 'gui/Layout.cs', 'gui/Services.cs', 'gui/SessionService.cs', 'gui/UIService.cs', 'gui/WidgetGroup.cs', ), dependencies: gtk_sharp_2_dep, cs_args: ['-r:Mono.Posix', '-nowarn:0169'], link_with: [ buffers_lib, gui_areas_lib, gui_drawers_lib, plugins_lib, tools_export_lib, tools_find_lib, tools_lib, util_lib, ], install: true, install_dir: assembly_install_dir, ) gui_plugins_lib = library( 'Bless.Gui.Plugins', files( 'gui/plugins/BitwiseOperationsPlugin.cs', 'gui/plugins/ConversionTablePlugin.cs', 'gui/plugins/CopyOffsetPlugin.cs', 'gui/plugins/EditOperationsPlugin.cs', 'gui/plugins/FileExportPlugin.cs', 'gui/plugins/FileOperationsPlugin.cs', 'gui/plugins/FindReplacePlugin.cs', 'gui/plugins/GotoOffsetPlugin.cs', 'gui/plugins/HelpOperationsPlugin.cs', 'gui/plugins/HistoryPlugin.cs', 'gui/plugins/InfobarPlugin.cs', 'gui/plugins/PatternMatchHighlightPlugin.cs', 'gui/plugins/ProgressDisplayPlugin.cs', 'gui/plugins/SelectLayoutPlugin.cs', 'gui/plugins/SelectRangePlugin.cs', ), dependencies: gtk_sharp_2_dep, cs_args: ['-r:Mono.Posix', '-nowarn:0169'], link_with: [ buffers_lib, gui_areas_lib, gui_drawers_lib, gui_lib, plugins_lib, tools_find_lib, tools_lib, util_lib, ], install: true, install_dir: assembly_install_dir, ) gui_areas_plugins_lib = library( 'Bless.Gui.Areas.Plugins', files( 'gui/areas/AsciiArea.cs', 'gui/areas/BinaryArea.cs', 'gui/areas/DecimalArea.cs', 'gui/areas/GroupedArea.cs', 'gui/areas/HexArea.cs', 'gui/areas/OctalArea.cs', 'gui/areas/OffsetArea.cs', 'gui/areas/SeparatorArea.cs', ), dependencies: gtk_sharp_2_dep, link_with: [ buffers_lib, gui_areas_lib, gui_drawers_lib, plugins_lib, util_lib, ], install: true, install_dir: assembly_install_dir, ) tools_export_plugins_lib = library( 'Bless.Tools.Export.Plugins', files( 'tools/export/plugins/HTMLExportBuilder.cs', 'tools/export/plugins/HTMLExportPlugin.cs', 'tools/export/plugins/TextExportBuilder.cs', 'tools/export/plugins/TextExportPlugin.cs', ), cs_args: ['-r:Mono.Posix'], link_with: [ buffers_lib, plugins_lib, tools_export_lib, util_lib, ], install: true, install_dir: assembly_install_dir, ) bless = executable( 'bless', files('gui/MainWindow.cs'), dependencies: gtk_sharp_2_dep, cs_args: ['-r:Mono.Posix', '-nowarn:0169'], link_with: [ buffers_lib, gui_areas_lib, gui_areas_plugins_lib, gui_drawers_lib, gui_lib, gui_plugins_lib, plugins_lib, tools_export_lib, tools_find_lib, tools_lib, util_lib, ], install: true, install_dir: assembly_install_dir, ) bless-0.6.3/src/plugins/000077500000000000000000000000001374060072200151015ustar00rootroot00000000000000bless-0.6.3/src/plugins/AreaPlugin.cs000066400000000000000000000020661374060072200174630ustar00rootroot00000000000000// created on 6/7/2007 at 3:50 PM /* * Copyright (c) 2006, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System.IO; using Bless.Gui.Areas; namespace Bless.Plugins { public class AreaPlugin : Plugin { protected AreaPlugin() { } public virtual Area CreateArea(AreaGroup ag) { return null; } } }bless-0.6.3/src/plugins/ExportPlugin.cs000066400000000000000000000020441374060072200200700ustar00rootroot00000000000000/* * Copyright (c) 2006, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System.IO; using Bless.Tools.Export; namespace Bless.Plugins { public class ExportPlugin : Plugin { protected ExportPlugin() { } public virtual IExportBuilder CreateBuilder(Stream s) { return null; } } }bless-0.6.3/src/plugins/GuiPlugin.cs000066400000000000000000000051601374060072200173350ustar00rootroot00000000000000// created on 4/28/2006 at 4:57 PM /* * Copyright (c) 2006, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using Gtk; namespace Bless.Plugins { public class GuiPlugin : Plugin { public GuiPlugin() { } protected Widget GetDataBook(Window win) { VBox vbox = (VBox)win.Child; foreach (Widget child in vbox.Children) { //System.Console.WriteLine("Child: {0}", child.GetType().ToString()); if (child.GetType() == typeof(HBox)) { foreach (Widget child1 in ((HBox)child).Children) { if (child1.GetType().ToString() == "Bless.Gui.DataBook") return child1; } } } return null; } protected Widget GetMenuBar(Window win) { VBox vbox = (VBox)win.Child; foreach (Widget child in vbox.Children) { //System.Console.WriteLine("Child: {0}", child.GetType().ToString()); if (child.GetType() == typeof(MenuBar)) { return child; } } return null; } protected Widget GetWidgetGroup(Window win, int n) { VBox vbox = (VBox)win.Child; int i = 0; foreach (Widget child in vbox.Children) { //System.Console.WriteLine("Child: {0}", child.GetType().ToString()); if (child.GetType().ToString() == "Bless.Gui.WidgetGroup") { if (i == n) return child; else i++; } } return null; } protected Widget GetSideWidgetGroup(Window win, int n) { VBox vbox = (VBox)win.Child; int i = 0; HBox hbox = null; foreach (Widget child in vbox.Children) { System.Console.WriteLine("Child: {0}", child.GetType().ToString()); if (child.GetType().ToString() == "Gtk.HBox") { hbox = (HBox)child; break; } } if (hbox == null) return null; foreach (Widget child in hbox.Children) { System.Console.WriteLine("Child: {0}", child.GetType().ToString()); if (child.GetType().ToString() == "Bless.Gui.WidgetGroup") { if (i == n) return child; else i++; } } return null; } } } bless-0.6.3/src/plugins/IPluginPreferences.cs000066400000000000000000000016741374060072200211710ustar00rootroot00000000000000/* * Copyright (c) 2008, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ public interface IPluginPreferences { Gtk.Widget Widget { get; } void SavePreferences(); void LoadPreferences(); } bless-0.6.3/src/plugins/Plugin.cs000066400000000000000000000034511374060072200166710ustar00rootroot00000000000000/* * Copyright (c) 2006, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.Collections.Generic; namespace Bless.Plugins { public class Plugin { protected string name; protected string author; protected string description; protected bool loaded; protected List dependencies; protected List loadAfter; public Plugin() { dependencies = new List(); loadAfter = new List(); } public virtual bool Load() { return false; } public virtual bool UnLoad() { return false; } public string Name { get { return name; } set { name = value; } } public string Author { get { return author;} set { author = value; } } public string Description { get { return description; } set { description = value; } } public bool Loaded { get { return loaded; } } public IList Dependencies { get { return dependencies; } } public IList LoadAfter { get { return loadAfter; } } public virtual IPluginPreferences PluginPreferences { get { return null; } } } } bless-0.6.3/src/plugins/PluginManager.cs000066400000000000000000000114221374060072200201610ustar00rootroot00000000000000/* * Copyright (c) 2006, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Reflection; using System.IO; using System.Globalization; using Bless.Util; namespace Bless.Plugins { public class PluginDependencyException : Exception { public PluginDependencyException(string msg) : base(msg) { } } public class PluginManager { Dictionary plugins; Type[] ctorArgTypes; object[] ctorArgs; Type pluginType; private PluginManager(Type pluginType, object[] args) { plugins = new Dictionary(); this.pluginType = pluginType; ctorArgTypes = new Type[args.Length]; ctorArgs = args; for (int i = 0; i < ctorArgs.Length; i++) ctorArgTypes[i] = ctorArgs[i].GetType(); // find system-wide plugins string systemPluginDir = FileResourcePath.GetBinPath(); string[] systemPluginFiles = Directory.GetFiles(systemPluginDir); CompareInfo compare = CultureInfo.InvariantCulture.CompareInfo; foreach (string file in systemPluginFiles) { if (compare.IndexOf(file, "plugin", CompareOptions.IgnoreCase) >= 0 && file.EndsWith(".dll")) { //Console.WriteLine("Searching File {0}", file); AddPluginFile(file); } } try { // find local user plugins string userPluginDir = FileResourcePath.GetUserPath("plugins"); string[] userPluginFiles = Directory.GetFiles(userPluginDir); foreach (string file in userPluginFiles) { if (compare.IndexOf(file, "plugin", CompareOptions.IgnoreCase) >= 0 && file.EndsWith(".dll")) { //Console.WriteLine("Searching File {0}", file); AddPluginFile(file); } } } catch (IOException e) { System.Console.WriteLine("Failed to open plugins directory: " + e.Message); } } private void AddPluginFile(string file) { try { Assembly asm = Assembly.LoadFile(file); Type[] types = asm.GetTypes(); foreach(Type t in types) { if (t.BaseType == pluginType) { //Console.WriteLine(" Found Type {0}", t.FullName); ConstructorInfo ctor = t.GetConstructor(ctorArgTypes); AddToPluginCollection((Plugin)ctor.Invoke(ctorArgs)); } } } catch (Exception e) { System.Console.WriteLine(e.Message); } } private void AddToPluginCollection(Plugin plugin) { plugins.Add(plugin.Name, plugin); //System.Console.WriteLine("Added plugin {0}", plugin.Name); } public bool LoadPlugin(Plugin plugin) { StringCollection visited = new StringCollection(); return LoadPluginInternal(plugin, visited); } private bool LoadPluginInternal(Plugin plugin, StringCollection visited) { visited.Add(plugin.Name); if (plugin.Loaded) return true; foreach(string dep in plugin.Dependencies) { if (visited.Contains(dep)) throw new PluginDependencyException("Cyclic dependency detected!"); if (!plugins.ContainsKey(dep)) throw new PluginDependencyException(string.Format("Cannot find plugin '{0}' needed by '{1}'", dep, plugin.Name)); if (LoadPluginInternal(plugins[dep], visited) == false) return false; } foreach(string la in plugin.LoadAfter) { if (visited.Contains(la)) throw new PluginDependencyException("Cyclic LoadAfter association detected!"); if (plugins.ContainsKey(la)) LoadPluginInternal(plugins[la], visited); } return plugin.Load(); } public Plugin[] Plugins { get { Plugin[] pa = new Plugin[plugins.Count]; int i = 0; foreach (Plugin p in plugins.Values) pa[i++] = p; return pa; } } static Dictionary pluginManagers = new Dictionary(); public static void AddForType(Type pluginType, object[] args) { PluginManager pm = new PluginManager(pluginType, args); pluginManagers[pluginType] = pm; } public static PluginManager GetForType(Type pluginType) { PluginManager ret = null; if (pluginManagers.ContainsKey(pluginType)) { ret = pluginManagers[pluginType]; } return ret; } public static IEnumerable> AllManagers { get { return pluginManagers; } } } } bless-0.6.3/src/tools/000077500000000000000000000000001374060072200145605ustar00rootroot00000000000000bless-0.6.3/src/tools/History.cs000066400000000000000000000057711374060072200165620ustar00rootroot00000000000000// created on 4/20/2005 at 2:14 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.Collections.Generic; using System.Xml; using System.IO; namespace Bless.Tools { /// /// A class that handles recently used files history (singleton) /// public class History { List files; int maxSize; static History instance; /// /// The current history /// static public History Instance { get { if (instance == null) instance = new History(5); return instance; } } ///The file in the history public List Files { get { return files; } } ///The maximum size of the history public int MaxSize { get { return maxSize; } } ///Create history with maximum size 'n' private History(int n) { files = new List(n); maxSize = n; } ///Add a file to the history public void Add(string path) { if (files.Remove(path) == true) { files.Insert(0, path); } else { if (files.Count == maxSize) files.RemoveAt(files.Count - 1); files.Insert(0, path); } if (Changed != null) Changed(this); } ///Load history from an xml file public void Load(string path) { XmlDocument xmlDoc = new XmlDocument(); xmlDoc.Load(path); XmlNodeList fileList = xmlDoc.GetElementsByTagName("file"); foreach(XmlNode fileNode in fileList) { this.Add(fileNode.InnerText); } } ///Save history to an xml file public void Save(string path) { XmlTextWriter xml = new XmlTextWriter(path, null); xml.Formatting = Formatting.Indented; xml.Indentation = 1; xml.IndentChar = '\t'; xml.WriteStartDocument(true); xml.WriteStartElement(null, "history", null); // save them in reverse order // so that they are loaded normally for (int i = files.Count - 1; i >= 0 ; i--) { xml.WriteStartElement(null, "file", null); xml.WriteString(files[i]); xml.WriteEndElement(); } xml.WriteEndElement(); xml.WriteEndDocument(); xml.Close(); } public delegate void HistoryChangedHandler(History his); //Emitted when history changes public event HistoryChangedHandler Changed; } } // end namespace bless-0.6.3/src/tools/Preferences.cs000066400000000000000000000140621374060072200173530ustar00rootroot00000000000000// created on 5/24/2005 at 1:14 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.Xml; using System.Collections; namespace Bless.Tools { public delegate void PreferencesChangedHandler(Preferences prefs); /// /// A class that holds the application preferences (using singletons) /// public class Preferences { Hashtable prefs; string autoSavePath; static Preferences instance = null; static Preferences defaultPrefs = null; static PreferencesProxy proxy = null; /// /// The current preferences /// static public Preferences Instance { get { if (instance == null) instance = new Preferences(); return instance; } } /// /// The default preferences /// static public Preferences Default { get { if (defaultPrefs == null) defaultPrefs = new Preferences(); return defaultPrefs; } } static public PreferencesProxy Proxy { get { if (proxy == null) proxy = new PreferencesProxy(Preferences.Instance); return proxy; } } private Preferences() { prefs = new Hashtable(); autoSavePath = null; notifyWhenSetting = true; } /// /// Get or Set the value of a preference /// public string this[string key] { get { string s = (string)prefs[key]; if (s == null) s = string.Empty; return s; } set { prefs[key] = value; // save the preferences if autoSavePath is set // ignore exceptions try { if (autoSavePath != null) Save(autoSavePath); } catch (Exception e) { System.Console.WriteLine(e.Message); } if (notifyWhenSetting) Preferences.Proxy.Change(key, value, "__Preferences__"); } } public string AutoSavePath { get { return autoSavePath; } set { autoSavePath = value; } } public IEnumerator GetEnumerator() { return prefs.GetEnumerator(); } public void SetWithoutNotify(string pref, string val) { notifyWhenSetting = false; this[pref] = val; notifyWhenSetting = true; } /// /// Save preferences to an Xml file /// public void Save(string path) { using (XmlTextWriter xml = new XmlTextWriter(path, null)) { xml.Formatting = Formatting.Indented; xml.Indentation = 1; xml.IndentChar = '\t'; xml.WriteStartDocument(); xml.WriteStartElement(null, "preferences", null); foreach (DictionaryEntry entry in prefs) { xml.WriteStartElement(null, "pref", null); xml.WriteStartAttribute(null, "name", null); xml.WriteString((string)entry.Key); xml.WriteEndAttribute(); xml.WriteString((string)entry.Value); xml.WriteEndElement(); } xml.WriteEndElement(); xml.WriteEndDocument(); } } /// /// Load preferences from an Xml file /// public void Load(string path) { using (XmlReader xmlReader = XmlReader.Create(path)) { XmlDocument xmlDoc = new XmlDocument(); xmlDoc.Load(xmlReader); XmlNodeList prefList = xmlDoc.GetElementsByTagName("pref"); foreach(XmlNode prefNode in prefList) { XmlAttributeCollection attrColl = prefNode.Attributes; string name = attrColl["name"].Value; prefs[name] = prefNode.InnerText; } } } /// /// Load preferences from another Preferences instance /// public void Load(Preferences p) { if (p != null) { foreach (DictionaryEntry entry in p) prefs[entry.Key] = entry.Value; } } /// /// Display preferences /// public void Display() { foreach (DictionaryEntry entry in prefs) { System.Console.WriteLine("[{0}]: {1}", entry.Key, entry.Value); } } private bool notifyWhenSetting; } public class PreferencesProxy { Hashtable prefSubscribers; Preferences prefs; Hashtable currentlyHandling; public PreferencesProxy(Preferences prefs) { prefSubscribers = new Hashtable(); currentlyHandling = new Hashtable(); this.prefs = prefs; this.enable = true; } public void Subscribe(string pref, string id, PreferencesChangedHandler handler) { if (!prefSubscribers.Contains(pref)) prefSubscribers[pref] = new Hashtable(); (prefSubscribers[pref] as Hashtable).Add(id, handler); } public void Unsubscribe(string pref, string id) { if (!prefSubscribers.Contains(pref)) return; (prefSubscribers[pref] as Hashtable).Remove(id); } public void Change(string pref, string val, string id) { if (enable == false) return; if (currentlyHandling.Contains(pref)) return; if (id != "__Preferences__") { prefs.SetWithoutNotify(pref, val); } if (!prefSubscribers.Contains(pref)) return; currentlyHandling.Add(pref, null); foreach(DictionaryEntry subscriber in (prefSubscribers[pref] as Hashtable)) if ((subscriber.Key as string) != id) { (subscriber.Value as PreferencesChangedHandler)(prefs); } currentlyHandling.Remove(pref); } public void NotifyAll() { if (enable == false) return; foreach(DictionaryEntry prefSub in prefSubscribers) { currentlyHandling.Add(prefSub.Key, null); foreach(DictionaryEntry subscriber in (prefSub.Value as Hashtable)) (subscriber.Value as PreferencesChangedHandler)(prefs); currentlyHandling.Remove(prefSub.Key); } } bool enable; /// /// Enable or disable emission of the Changed event /// public bool Enable { get { return enable; } set { enable = value; } } } } // end namespace bless-0.6.3/src/tools/Session.cs000066400000000000000000000160121374060072200165320ustar00rootroot00000000000000// created on 4/15/2005 at 11:44 AM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.Collections; using System.Xml; using System.IO; namespace Bless.Tools { /// /// Handles the saving and loading of sessions /// (files that describe the current workspace) /// public class Session { int windowWidth; int windowHeight; string activeFile; ArrayList files; public ArrayList Files { get { return files; } } public int WindowWidth { get { return windowWidth;} set { windowWidth = value;} } public int WindowHeight { get { return windowHeight;} set { windowHeight = value;} } public string ActiveFile { get { return activeFile; } set { activeFile = value; } } public Session() { files = new ArrayList(); activeFile = string.Empty; } public void AddFile(string name, long offset, long cursorOffset, int cursorDigit, string layout, int focusedArea) { string path = Path.GetFullPath(name); SessionFileInfo sfi = new SessionFileInfo(path, offset, cursorOffset, cursorDigit, layout, focusedArea); files.Add(sfi); } public void Save(string path) { using (XmlTextWriter xml = new XmlTextWriter(path, null)) { xml.Formatting = Formatting.Indented; xml.Indentation = 1; xml.IndentChar = '\t'; xml.WriteStartDocument(); xml.WriteStartElement(null, "session", null); xml.WriteStartElement(null, "windowheight", null); xml.WriteString(windowHeight.ToString()); xml.WriteEndElement(); xml.WriteStartElement(null, "windowwidth", null); xml.WriteString(windowWidth.ToString()); xml.WriteEndElement(); xml.WriteStartElement(null, "activefile", null); xml.WriteString(activeFile); xml.WriteEndElement(); foreach(SessionFileInfo sfi in files) { xml.WriteStartElement(null, "file", null); xml.WriteStartElement(null, "path", null); xml.WriteString(sfi.Path); xml.WriteEndElement(); xml.WriteStartElement(null, "offset", null); xml.WriteString(sfi.Offset.ToString()); xml.WriteEndElement(); xml.WriteStartElement(null, "cursoroffset", null); xml.WriteString(sfi.CursorOffset.ToString()); xml.WriteEndElement(); xml.WriteStartElement(null, "cursordigit", null); xml.WriteString(sfi.CursorDigit.ToString()); xml.WriteEndElement(); xml.WriteStartElement(null, "layout", null); xml.WriteString(sfi.Layout); xml.WriteEndElement(); xml.WriteStartElement(null, "focusedarea", null); xml.WriteString(sfi.FocusedArea.ToString()); xml.WriteEndElement(); xml.WriteEndElement(); } xml.WriteEndElement(); xml.WriteEndDocument(); } } public void Load(string path) { using (XmlReader xmlReader = XmlReader.Create(path)) { XmlDocument xmlDoc = new XmlDocument(); xmlDoc.Load(xmlReader); XmlNodeList fileList = xmlDoc.GetElementsByTagName("file"); foreach(XmlNode fileNode in fileList) { XmlNodeList childNodes = fileNode.ChildNodes; SessionFileInfo sfi = new SessionFileInfo(); foreach(XmlNode node in childNodes) { switch (node.Name) { case "path": sfi.Path = node.InnerText; break; case "offset": sfi.Offset = Convert.ToInt64(node.InnerText); break; case "cursoroffset": sfi.CursorOffset = Convert.ToInt64(node.InnerText); break; case "cursordigit": sfi.CursorDigit = Convert.ToInt32(node.InnerText); break; case "layout": sfi.Layout = node.InnerText; break; case "focusedarea": sfi.FocusedArea = Convert.ToInt32(node.InnerText); break; default: break; } } files.Add(sfi); } XmlNodeList heightList = xmlDoc.GetElementsByTagName("windowheight"); foreach(XmlNode heightNode in heightList) { windowHeight = Convert.ToInt32(heightNode.InnerText); } XmlNodeList widthList = xmlDoc.GetElementsByTagName("windowwidth"); foreach(XmlNode widthNode in widthList) { windowWidth = Convert.ToInt32(widthNode.InnerText); } XmlNodeList activeList = xmlDoc.GetElementsByTagName("activefile"); foreach(XmlNode activeNode in activeList) { activeFile = activeNode.InnerText; } } } } /// /// Holds information about a file as part of a session /// public class SessionFileInfo { public string Path; public long Offset; public long CursorOffset; public int CursorDigit; public string Layout; public int FocusedArea; public SessionFileInfo() { } public SessionFileInfo(string path, long offset, long cursorOffset, int cursorDigit, string layout, int focusedArea) { Path = path; Offset = offset; CursorOffset = cursorOffset; CursorDigit = cursorDigit; Layout = layout; FocusedArea = focusedArea; } } } // end namespace bless-0.6.3/src/tools/export/000077500000000000000000000000001374060072200161015ustar00rootroot00000000000000bless-0.6.3/src/tools/export/ExporterOperation.cs000066400000000000000000000041301374060072200221170ustar00rootroot00000000000000// created on 12/4/2006 at 9:36 PM /* * Copyright (c) 2006, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using Bless.Util; using Bless.Buffers; namespace Bless.Tools.Export { public class ExportOperation : ThreadedAsyncOperation { IExporter exporter; IBuffer buffer; long rangeStart; long rangeEnd; public IExporter Exporter { get { return exporter; } } public ExportOperation(IExporter ex, IBuffer buf, long start, long end, ProgressCallback progressCb, AsyncCallback endCb) : base(progressCb, endCb, true) { exporter = ex; buffer = buf; rangeStart = start; rangeEnd = end; } private double CalculatePercentDone() { return ((double)(exporter.CurrentPosition - rangeStart)) / (rangeEnd - rangeStart); } protected override bool StartProgress() { return progressCallback(CalculatePercentDone(), ProgressAction.Show); } protected override bool UpdateProgress() { return progressCallback(CalculatePercentDone(), ProgressAction.Update); } protected override bool EndProgress() { return progressCallback(CalculatePercentDone(), ProgressAction.Hide); } protected override void DoOperation() { System.Console.WriteLine("Starting export"); exporter.Export(buffer, rangeStart, rangeEnd, ref cancelled); System.Console.WriteLine("Ending export"); } protected override void EndOperation() { } } } bless-0.6.3/src/tools/export/IExportBuilder.cs000066400000000000000000000030001374060072200213220ustar00rootroot00000000000000/* * Copyright (c) 2006, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System.IO; using System.Collections; using Bless.Buffers; namespace Bless.Tools.Export { public struct BuildBytesInfo { public int Count; public char Type; public string Prefix; public string Suffix; public string Separator; public string Empty; public Hashtable Commands; } /// /// A builder that is used to export bytes /// public interface IExportBuilder { void BuildPrologue(); void BuildEpilogue(); int BuildBytes(IBuffer buffer, long offset, BuildBytesInfo info); void BuildString(string str); void BuildCharacter(char c); void BuildAlignment(int align); void BuildOffset(long offset, int length, char type); Stream OutputStream { get; } } } bless-0.6.3/src/tools/export/IExporter.cs000066400000000000000000000022411374060072200203500ustar00rootroot00000000000000/* * Copyright (c) 2006, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using Bless.Buffers; using System.IO; namespace Bless.Tools.Export { /// /// Exports a range of data to various formats /// public interface IExporter { void Export(IBuffer buffer, long start, long end, ref bool cancelled); IExportBuilder Builder { get; } long CurrentPosition { get; } } } // end namespacebless-0.6.3/src/tools/export/IPatternExporter.cs000066400000000000000000000021421374060072200217060ustar00rootroot00000000000000/* * Copyright (c) 2006, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using Bless.Buffers; using System.IO; namespace Bless.Tools.Export { /// /// Exports a range of data to various formats /// using a specific pattern /// public interface IPatternExporter : IExporter { string Pattern { get; set; } } } // end namespacebless-0.6.3/src/tools/export/InterpretedPatternExporter.cs000066400000000000000000000165171374060072200240160ustar00rootroot00000000000000/* * Copyright (c) 2006, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.Text; using System.Collections.Generic; using System.Collections; using Bless.Buffers; using Bless.Util; using Mono.Unix; namespace Bless.Tools.Export { /// /// Exports a range of data to various formats /// using a specific pattern which is constantly /// interpreted /// public class InterpretedPatternExporter : IPatternExporter { IExportBuilder builder; string pattern; int patternIndex; char characterData; string stringData; Stack positionStack; long rangeStart; long rangeEnd; long bufPos; IBuffer buffer; enum Token { LeftBracket, RightBracket, Percent, Character, String, Error, End } public InterpretedPatternExporter(IExportBuilder ieb) { builder = ieb; positionStack = new Stack(); } public void Export(IBuffer buf, long start, long end, ref bool cancelled) { buffer = buf; rangeStart = start; rangeEnd = end; bufPos = rangeStart; long prevLoop = bufPos; bool finished = false; builder.BuildAlignment(1); Hashtable cmds = new Hashtable(); builder.BuildPrologue(); while (!finished && !cancelled) { Token tok = NextToken(); switch (tok) { case Token.LeftBracket: SavePosition(bufPos); break; case Token.RightBracket: bufPos = RestorePosition(); break; case Token.Percent: cmds.Clear(); // try to parse a command tok = ParseCommand(cmds); // if we ended at another '%' parse was succesful if (tok == Token.Percent) bufPos += ExecuteCommand(cmds); else // otherwise mark an error tok = Token.Error; break; case Token.Character: builder.BuildCharacter(characterData); break; case Token.String: builder.BuildString(stringData); break; case Token.End: if (bufPos <= rangeEnd && prevLoop < bufPos) { prevLoop = bufPos; RestartInterpreter(); } // if we reached the end of the pattern and we haven't moved forwards // in the file, this is never going to end! else if (prevLoop >= bufPos && bufPos <= rangeEnd) throw new FormatException(Catalog.GetString("Pattern causes infinite loop")); else finished = true; break; default: break; } if (tok == Token.Error) throw new FormatException(string.Format(Catalog.GetString("Error at format position {0}"), patternIndex)); } if (!cancelled) builder.BuildEpilogue(); } public IExportBuilder Builder { get { return builder; } } public long CurrentPosition { get { return bufPos; } } public string Pattern { get { return pattern; } set { pattern = value; } } /// /// Execute the command described by the cmds hashtable /// private int ExecuteCommand(Hashtable cmds) { // Export command if (cmds.Contains('E')) { BuildBytesInfo bbi = new BuildBytesInfo(); bbi.Count = 1; if ((cmds['E'] as string) != "") bbi.Count = Convert.ToInt32(cmds['E'] as string); if (cmds.Contains('p')) bbi.Prefix = cmds['p'] as string; if (cmds.Contains('s')) bbi.Suffix = cmds['s'] as string; if (cmds.Contains('x')) bbi.Separator = cmds['x'] as string; if (cmds.Contains('e')) bbi.Empty = cmds['e'] as string; if (cmds.Contains('t')) bbi.Type = Convert.ToChar(cmds['t'] as string); else bbi.Type = 'H'; bbi.Commands = cmds; return builder.BuildBytes(buffer, bufPos, bbi); } // Ignore command if (cmds.Contains('I')) { if ((cmds['I'] as string) == "") return 1; else return Convert.ToInt32(cmds['I'] as string); } // Offset command if (cmds.Contains('O')) { char type = 'H'; if (cmds.Contains('t')) type = Convert.ToChar(cmds['t'] as string); int length = 8; if ((cmds['O'] as string) != "") length = Convert.ToInt32(cmds['O'] as string); builder.BuildOffset(bufPos, length, type); return 0; } // Alignment command if (cmds.Contains('A')) { builder.BuildAlignment(Convert.ToInt32(cmds['A'] as string)); return 0; } return 0; } private void SavePosition(long cur) { positionStack.Push(cur); } private long RestorePosition() { return positionStack.Pop(); } private void RestartInterpreter() { patternIndex = 0; } private Token NextToken() { if (patternIndex >= pattern.Length) return Token.End; Token tok = Token.Error; switch (pattern[patternIndex]) { case '[': patternIndex++; tok = Token.LeftBracket; break; case ']': patternIndex++; tok = Token.RightBracket; break; case '%': patternIndex++; tok = Token.Percent; break; case '"': tok = ParseString(); break; case '\\': tok = ParseEscapedCharacter(); break; default: characterData = pattern[patternIndex]; patternIndex++; tok = Token.Character; break; } return tok; } private Token ParseString() { StringBuilder sb = new StringBuilder(); patternIndex++; bool finished = false; while (patternIndex < pattern.Length && !finished) { switch (pattern[patternIndex]) { case '\\': Token tok = ParseEscapedCharacter(); if (tok == Token.Error) return Token.Error; else sb.Append(characterData); break; case '"': finished = true; patternIndex++; break; default: sb.Append(pattern[patternIndex]); patternIndex++; break; } } if (!finished) return Token.Error; stringData = sb.ToString(); return Token.String; } private Token ParseEscapedCharacter() { Token ret = Token.Error; if (patternIndex + 1 < pattern.Length) { switch (pattern[patternIndex + 1]) { case 'n': characterData = '\n'; ret = Token.Character; break; case 't': characterData = '\t'; ret = Token.Character; break; default: characterData = pattern[patternIndex + 1]; ret = Token.Character; break; } } else ret = Token.Error; patternIndex += 2; return ret; } /// /// Parse a pattern command eg %E"4"p"0x"% /// private Token ParseCommand(Hashtable cmds) { bool finished = false; Token tok = Token.Error; char currentChar = ' '; while (!finished) { tok = NextToken(); switch (tok) { case Token.Percent: finished = true; break; case Token.Character: currentChar = characterData; cmds[currentChar] = string.Empty; break; case Token.String: cmds[currentChar] = stringData; break; case Token.End: finished = true; break; default: tok = Token.Error; finished = true; break; } } return tok; } } } bless-0.6.3/src/tools/export/plugins/000077500000000000000000000000001374060072200175625ustar00rootroot00000000000000bless-0.6.3/src/tools/export/plugins/HTMLExportBuilder.cs000066400000000000000000000033251374060072200233710ustar00rootroot00000000000000// created on 12/5/2006 at 2:23 PM /* * Copyright (c) 2006, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System.IO; using Bless.Buffers; using Bless.Util; using Bless.Tools.Export; namespace Bless.Tools.Export.Plugins { /// /// A builder that exports bytes to HTML /// public class HTMLExportBuilder : TextExportBuilder { public HTMLExportBuilder(Stream stream) : base(stream) { } public override void BuildPrologue() { System.Console.WriteLine("Writing prologue"); BuildString("
");
	}

	public override void BuildEpilogue()
	{
		System.Console.WriteLine("Writing epilogue");
		BuildString("
"); } protected override int BuildByte(IBuffer buf, long offset, BuildBytesInfo info, bool dummy) { if (offset % 2 == 0) BuildString(""); int n = base.BuildByte(buf, offset, info, dummy); if (offset % 2 == 0) BuildString(""); return n; } } } //end namespacebless-0.6.3/src/tools/export/plugins/HTMLExportPlugin.cs000066400000000000000000000025151374060072200232410ustar00rootroot00000000000000// created on 12/5/2006 at 2:23 PM // created on 12/3/2006 at 4:07 PM /* * Copyright (c) 2006, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System.IO; using Bless.Plugins; using Bless.Tools.Export; using Mono.Unix; namespace Bless.Tools.Export.Plugins { public class HTMLExportPlugin : ExportPlugin { public HTMLExportPlugin() { name = "HTMLExport"; author = "Alexandros Frantzis"; description = Catalog.GetString("Export as HTML"); dependencies.Add("TextExport"); } public override IExportBuilder CreateBuilder(Stream s) { return new HTMLExportBuilder(s); } } } bless-0.6.3/src/tools/export/plugins/TextExportBuilder.cs000066400000000000000000000116551374060072200235560ustar00rootroot00000000000000/* * Copyright (c) 2006, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.IO; using Bless.Buffers; using Bless.Util; using Bless.Tools.Export; namespace Bless.Tools.Export.Plugins { /// /// A builder that exports bytes to text /// public class TextExportBuilder : IExportBuilder { protected StreamWriter writer; protected int alignment; public TextExportBuilder(Stream stream) { writer = new StreamWriter(stream); alignment = 1; } public virtual void BuildPrologue() { } public virtual void BuildEpilogue() { } public virtual int BuildBytes(IBuffer buffer, long offset, BuildBytesInfo info) { int nwritten = 0; int count = info.Count; count -= MatchAlignment(offset, info); // emit the bytes (eg "__ __ 00 00") for (int i = 0; i < count; i++) { if (i != 0) BuildSeparator(info.Separator); nwritten += BuildByte(buffer, offset + i, info, false); } writer.Flush(); return nwritten; } public virtual void BuildString(string str) { writer.Write(str); writer.Flush(); } public virtual void BuildCharacter(char c) { writer.Write(c); writer.Flush(); } public virtual void BuildAlignment(int align) { alignment = align; } public virtual void BuildOffset(long offset, int length, char type) { long lowAlign = (offset / alignment) * alignment; bool lowercase; int numBase = GetBaseFromArgument(type, out lowercase); string str = BaseConverter.ConvertToString(lowAlign, numBase, false, lowercase, length); BuildByteData(str); } public Stream OutputStream { get { return writer.BaseStream; } } protected virtual int MatchAlignment(long offset, BuildBytesInfo info) { int count = 0; // match alignment // find lower alignment offset long lowAlign = (offset / alignment) * alignment; // fill with blanks (eg "__ __") for (long i = lowAlign; i < offset; i++) { if (i != lowAlign) BuildSeparator(info.Separator); BuildByte(null, 0, info, true); count++; } // if alignment adjustments had to be made // emit one more separator (eg "__ __ " <-- notice last space) if (lowAlign != offset) writer.Write(info.Separator); return count; } protected virtual int BuildByte(IBuffer buffer, long offset, BuildBytesInfo info, bool dummy) { string str; int nwritten = 0; byte b = 0; if (dummy == true || offset >= buffer.Size) { dummy = true; } else { nwritten++; b = buffer[offset]; } if (info.Type == 'A') { // Replace unprintable characters with dots if (b < 32 || b >= 127) { str = "."; } else str = System.Text.Encoding.ASCII.GetString(new byte[]{b}); } else { bool lowercase; int numBase = GetBaseFromArgument(info.Type, out lowercase); str = BaseConverter.ConvertToString(b, numBase, false, lowercase, 0); } if (!dummy && info.Prefix != null) BuildPrefix(info.Prefix); else BuildEmpty(info.Prefix, " "); if (!dummy && str != null) { BuildByteData(str); } else if (info.Empty != null) BuildEmpty(str, info.Empty); else BuildEmpty(str, " "); if (!dummy && info.Suffix != null) BuildSuffix(info.Suffix); else BuildEmpty(info.Suffix, " "); return nwritten; } protected virtual void BuildSeparator(string separator) { writer.Write(separator); } protected virtual void BuildEmpty(string str, string empty) { if (str == null) return; for (int i = str.Length; i > 0;) { if (empty.Length <= i) { writer.Write(empty); i -= empty.Length; } else { writer.Write(empty.Substring(0, i)); i = 0; } } } protected virtual void BuildPrefix(string str) { writer.Write(str); } protected virtual void BuildSuffix(string str) { writer.Write(str); } protected virtual void BuildByteData(string str) { writer.Write(str); } private int GetBaseFromArgument(char type, out bool lowercase) { int numBase = 0; lowercase = false; switch (type) { case 'H': numBase = 16; break; case 'h': numBase = 16; lowercase = true; break; case 'D': numBase = 10; break; case 'O': numBase = 8; break; case 'B': numBase = 2; break; default: break; } return numBase; } } } //end namespace bless-0.6.3/src/tools/export/plugins/TextExportPlugin.cs000066400000000000000000000024101374060072200234130ustar00rootroot00000000000000// created on 12/3/2006 at 4:07 PM /* * Copyright (c) 2006, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System.IO; using Bless.Plugins; using Bless.Tools.Export; using Mono.Unix; namespace Bless.Tools.Export.Plugins { public class TextExportPlugin : ExportPlugin { public TextExportPlugin() { name = "TextExport"; author = "Alexandros Frantzis"; description = Catalog.GetString("Export as Text"); } public override IExportBuilder CreateBuilder(Stream s) { return new TextExportBuilder(s); } } } bless-0.6.3/src/tools/find/000077500000000000000000000000001374060072200155005ustar00rootroot00000000000000bless-0.6.3/src/tools/find/BMFindStrategy.cs000066400000000000000000000142341374060072200206550ustar00rootroot00000000000000// created on 2/15/2005 at 12:32 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using Bless.Util; using Bless.Buffers; namespace Bless.Tools.Find { /// A Boyer-Moore finder utilizing only skip-tables (bad-character shifts) public class BMFindStrategy : IFindStrategy { byte[] pattern; ByteBuffer buffer; long pos; bool cancelled; int[] skipTable; int[] skipTableReverse; /// /// Create the forward and reverse skip tables /// for boyer-moore based searches /// void UpdateSkipTables() { int len = skipTable.Length; int patLen = pattern.Length; for (int i = 0; i < len; i++) { skipTable[i] = patLen; skipTableReverse[i] = patLen; } for (int i = 0; i < patLen;i++) skipTable[pattern[i]] = patLen - i - 1; for (int i = patLen - 1; i >= 0;i--) skipTableReverse[pattern[i]] = i; } public BMFindStrategy() { pattern = new byte[0]; skipTable = new int[256]; skipTableReverse = new int[256]; } public byte[] Pattern { set { pattern = (byte[])value.Clone(); UpdateSkipTables(); } get { return pattern; } } public ByteBuffer Buffer { get { return buffer; } set { buffer = value; pos = 0; } } public long Position { get { return pos;} set { pos = value; } } public bool Cancelled { get { return cancelled; } set { cancelled = value;} } ///Simple method to search forwards for a single byte Range FindNextSingle(long limit) { byte b = pattern[0]; while ((pos < limit) && buffer[pos] != b && !cancelled) pos++; if (pos >= limit || cancelled) return null; else { Range r = new Range(pos, pos); pos++; // next time start search from next byte return r; } } ///Simple method to search backwards for a single byte Range FindPreviousSingle(long limit) { byte b = pattern[0]; // start the search at the previous position pos--; while ((pos >= limit) && buffer[pos] != b && !cancelled) pos--; if (pos < 0 || cancelled) { // make sure pos is not negative if (pos < 0) pos = 0; return null; } else { Range r = new Range(pos, pos); return r; } } public Range FindNext(long limit) { int patLen = pattern.Length; long bufLen = buffer.Size; byte curByte = 0; int i = 0; // adjustment: search up to and including limit... limit++; // make sure limit is sane if (limit > bufLen) limit = bufLen; // if pattern is empty don't bother searching... if (patLen == 0) return null; // use simple method for 1 byte searches if (patLen == 1) return FindNextSingle(limit); // while buffer has more bytes to search while (pos <= limit - patLen && !cancelled) { // while bytes match and more bytes are left in the pattern, continue... for (i = patLen - 1; i >= 0; --i) { curByte = buffer[pos+i]; if (curByte != pattern[i]) break; } // if we found a match if (i < 0) { Range r = new Range(pos, pos + patLen - 1); pos++; // next time start search from next byte return r; } else {// shift int t = skipTable[curByte]; // can we use the skip value? if (patLen - i > t) { // ...no, because the "text" byte that caused the mismatch // has already been matched in the pattern and the skipTable[] // holds info only for the rightmost occurence of a byte. // eg TEXT: abcdcg -> The c causes the mismatch // PAT: aafdcg but has already been matched // SAFE SOLUTION: move the pattern one position to the right and continue // BETTER: use the complete BM algorithm with good-suffix shift pos += patLen - i; } else // ...yes pos += t - patLen + 1 + i; } // end shift } return null; } // this is like FindNext(), only we are searching backwards // so everything is reversed public Range FindPrevious(long limit) { int patLen = pattern.Length; byte curByte = 0; int i; // make sure limit is sane if (limit < 0) limit = 0; // if pattern is empty don't bother searching... if (patLen == 0) return null; // use simple method for 1 byte searches if (patLen == 1) return FindPreviousSingle(limit); // start the search at the previous position pos--; // while buffer has more bytes to search while (pos >= limit + patLen - 1 && !cancelled) { // while bytes match and more bytes are left in the pattern, continue... for (i = 0; i < patLen; ++i) { curByte = buffer[pos-patLen+1+i]; if (curByte != pattern[i]) break; } // if we found a match if (i >= patLen) { Range r = new Range(pos - patLen + 1, pos); return r; } else {// shift int t = skipTableReverse[curByte]; // can we use the skip value? if (i > t) { // ...no, because the "text" byte that caused the mismatch // has already been matched in the pattern and the skipTableReverse[] // holds info only for the leftmost occurence of a byte. // eg TEXT: abcdcg -> The c causes the mismatch // PAT: abcdfg but has already been matched // SAFE SOLUTION: move the pattern one position to the left and continue // BETTER: use the complete BM algorithm with good-suffix shift pos--; } else // ...yes pos -= t - i; } // end shift } // make sure pos is not negative if (pos < 0) pos = 0; return null; } public Range FindNext() { return FindNext(long.MaxValue -1); } public Range FindPrevious() { return FindPrevious(0); } } } //end namespace bless-0.6.3/src/tools/find/FindAsyncResult.cs000066400000000000000000000030761374060072200211120ustar00rootroot00000000000000// created on 3/31/2005 at 1:41 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using Bless.Util; using System; using System.Threading; namespace Bless.Tools.Find { /// /// Class to hold information about an asynchronous find operation /// public class FindAsyncResult: IAsyncResult { object asyncState; WaitHandle asyncWaitHandle; bool isCompleted; public FindAsyncResult(object state, WaitHandle handle, bool complete) { asyncState = state; asyncWaitHandle = handle; isCompleted = complete; } public object AsyncState { get { return asyncState;} } public WaitHandle AsyncWaitHandle { get { return asyncWaitHandle;} } public bool CompletedSynchronously { get { return false;} } public bool IsCompleted { get { return isCompleted;} } } } // end namespacebless-0.6.3/src/tools/find/FindOperations.cs000066400000000000000000000112671374060072200207620ustar00rootroot00000000000000// created on 3/31/2005 at 2:23 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.IO; using System.Threading; using Bless.Util; namespace Bless.Tools.Find { /// /// Generic find operation using an asynchronous threaded model of operation. /// public abstract class GenericFindOperation: ThreadedAsyncOperation { protected IFindStrategy strategy; protected Bless.Util.Range match; public IFindStrategy Strategy { get {return strategy;} } public Bless.Util.Range Match { get { return match; } } public GenericFindOperation(IFindStrategy ifs, ProgressCallback pc, AsyncCallback ac): base(pc, ac, true) { strategy = ifs; strategy.Cancelled = false; match = null; } protected override bool StartProgress() { return progressCallback(((double)strategy.Position) / strategy.Buffer.Size, ProgressAction.Show); } protected override bool UpdateProgress() { strategy.Cancelled = progressCallback(((double)strategy.Position) / strategy.Buffer.Size, ProgressAction.Update); return strategy.Cancelled; } protected override bool EndProgress() { return progressCallback(((double)strategy.Position) / strategy.Buffer.Size, ProgressAction.Hide); } protected override void DoOperation() { match = strategy.FindNext(); } protected override void EndOperation() { // re-allow buffer usage strategy.Buffer.ReadAllowed = true; strategy.Buffer.ModifyAllowed = true; strategy.Buffer.FileOperationsAllowed = true; } } /// /// Find Next operation using an asynchronous threaded model of operation. /// public class FindNextOperation: GenericFindOperation { public FindNextOperation(IFindStrategy ifs, ProgressCallback pc, AsyncCallback ac): base(ifs, pc, ac) { } protected override void DoOperation() { match = strategy.FindNext(); } } /// /// Find Previous operation using an asynchronous threaded model of operation. /// public class FindPreviousOperation: GenericFindOperation { public FindPreviousOperation(IFindStrategy ifs, ProgressCallback pc, AsyncCallback ac): base(ifs, pc, ac) { } protected override void DoOperation() { match = strategy.FindPrevious(); } } /// /// Replace All operation using an asynchronous threaded model of operation. /// public class ReplaceAllOperation: GenericFindOperation { byte[] replacePattern; Bless.Util.Range firstMatch; long numReplaced; public long NumReplaced { get { return numReplaced; } } public byte[] ReplacePattern { get { return replacePattern; } } public Bless.Util.Range FirstMatch { get { return firstMatch; } } public ReplaceAllOperation(IFindStrategy ifs, ProgressCallback pc, AsyncCallback ac, byte[] repPat): base(ifs, pc, ac) { replacePattern = repPat; } protected override void DoOperation() { Util.Range m; match = new Util.Range(); firstMatch = null; numReplaced = 0; strategy.Buffer.BeginActionChaining(); strategy.Buffer.ModifyAllowed = false; strategy.Buffer.FileOperationsAllowed = false; strategy.Buffer.EmitEvents = false; while ((m = strategy.FindNext()) != null) { if (firstMatch == null) { firstMatch = new Util.Range(m); } match.Start = m.Start; match.End = m.End; lock (strategy.Buffer.LockObj) { strategy.Buffer.ModifyAllowed = true; strategy.Buffer.Replace(m.Start, m.End, replacePattern); strategy.Buffer.ModifyAllowed = false; } // start next search after the replaced pattern strategy.Position = m.Start + replacePattern.Length; numReplaced++; } } protected override void EndOperation() { // re-allow buffer usage strategy.Buffer.ReadAllowed = true; strategy.Buffer.ModifyAllowed = true; strategy.Buffer.FileOperationsAllowed = true; strategy.Buffer.EmitEvents = true; strategy.Buffer.EmitPermissionsChanged(); strategy.Buffer.EmitChanged(); strategy.Buffer.EndActionChaining(); } } } // end namespace bless-0.6.3/src/tools/find/IFindStrategy.cs000066400000000000000000000023671374060072200205530ustar00rootroot00000000000000// created on 1/9/2005 at 1:14 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using Bless.Util; using Bless.Buffers; namespace Bless.Tools.Find { public interface IFindStrategy { byte[] Pattern { get; set; } ByteBuffer Buffer { get; set; } long Position { get; set; } Util.Range FindNext(); Util.Range FindPrevious(); Util.Range FindNext(long limit); Util.Range FindPrevious(long limit); bool Cancelled { get; set; } } } // end namespace bless-0.6.3/src/tools/find/IFinder.cs000066400000000000000000000024661374060072200173570ustar00rootroot00000000000000// created on 1/17/2005 at 4:58 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using Bless.Util; using Bless.Buffers; namespace Bless.Tools.Find { public delegate void FirstFindHandler(); public interface IFinder { IFindStrategy Strategy { get; set; } Util.Range LastFound { get; set; } event FirstFindHandler FirstFind; IAsyncResult FindNext(AsyncCallback ac); IAsyncResult FindPrevious(AsyncCallback ac); bool Replace(byte[] ba); IAsyncResult ReplaceAll(byte[] ba, AsyncCallback ac); } } // end namespace bless-0.6.3/src/tools/find/SimpleFindStrategy.cs000066400000000000000000000045211374060072200216060ustar00rootroot00000000000000// created on 1/9/2005 at 1:18 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using Bless.Util; using Bless.Buffers; namespace Bless.Tools.Find { /// A simple, brute-force finder class SimpleFindStrategy : IFindStrategy { byte[] pattern; ByteBuffer buffer; long pos; public SimpleFindStrategy() { pattern = new byte[0]; } public byte[] Pattern { set { pattern = (byte[])value.Clone(); } get { return pattern; } } public ByteBuffer Buffer { get { return buffer; } set { buffer = value; pos = 0; } } public long Position { get { return pos;} set { pos = value; } } public Range FindNext(long limit) { long len = buffer.Size; int plen = pattern.Length; int i = 0; if (limit > len) limit = len; while (pos < limit && i < plen) { if (buffer[pos] == pattern[i]) { i++; } else { if (i > 0) pos = pos - i + 1; i = 0; } pos++; } if (i == plen && plen > 0) return new Range(pos -plen, pos - 1); else return null; } public Range FindPrevious(long limit) { int plen = pattern.Length; int i = plen - 1; if (limit < 0) limit = 0; pos--; while (pos >= limit && i >= 0 ) { if (buffer[pos] == pattern[i]) { i--; } else { if (i < plen - 1) pos = pos + (plen - 1 - i) - 1; i = plen - 1; } pos--; } if (i == -1 && plen > 0) return new Range(pos + 1, pos + plen); else return null; } public Range FindNext() { return FindNext(long.MaxValue); } public Range FindPrevious() { return FindPrevious(0); } } } //end namespace bless-0.6.3/src/util/000077500000000000000000000000001374060072200143755ustar00rootroot00000000000000bless-0.6.3/src/util/BaseConverter.cs000066400000000000000000000076611374060072200175000ustar00rootroot00000000000000// created on 2/19/2005 at 9:40 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.Text; using Mono.Unix; namespace Bless.Util { ///Convert strings to numbers and vice-versa using a specified base public class BaseConverter { static public int[] DefaultMinDigits = new int[]{0, 0, 8, 6, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2}; // Don't allow instantiation private BaseConverter() { } ///Convinience method static public string ConvertToString(long num, int b) { return ConvertToString(num, b, false, false, 0); } ///Convert a number to string using the specified base static public string ConvertToString(long num, int b, bool prependPrefix, bool lowercase, int minDigits) { // make sure base is valid if (b < 2 || b > 16) return null; StringBuilder sb = new StringBuilder(64); char alpha = lowercase ? 'a' : 'A'; while (num > 0) { int rem = (int)(num % b); if (rem < 10) sb.Insert(0, (char)(rem + '0')); else sb.Insert(0, (char)(rem - 10 + alpha)); num = num / b; } // if minDigits == 0 use a minimum number of digits // which depends on the base used if (minDigits == 0) minDigits = DefaultMinDigits[b]; // pad number with zeroes, until it reaches the minimum length while (sb.Length < minDigits) sb.Insert(0, '0'); // prepend a prefix to mark the number base // (for octal and hexadecimal bases) if (prependPrefix) { if (b == 16) sb.Insert(0, "0x"); else if (b == 8 && sb[0] != '0') sb.Insert(0, '0'); } return sb.ToString(); } static private int CharToInt(char c, int b) { int ret = -1; if (c >= '0' && c <= '9') ret = c - '0'; else { c = Char.ToLower(c); if (c >= 'a' && c <= 'f') ret = c - 'a' + 10; } // if character is not valid or beyond base throw exception if (ret >= b || ret == -1) throw new FormatException(String.Format(Catalog.GetString("Character '{0}' is not valid in a number of base {1}."), c, b)); return ret; } ///Convert a string to a number using the specified base static public long ConvertToNum(string s, int startIndex, int endIndex, int b) { long val = 0; int i = startIndex; while (i <= endIndex) { val = b * val + CharToInt(s[i], b); i++; } return val; } static public long ConvertToNum(string s, int b) { return ConvertToNum(s, 0, s.Length - 1, b); } ///Convert a string to a number guessing the base from the string format static public long Parse(string s) { // trim the spaces from the string string trimStr = s.Trim(); int i = 0; int len = trimStr.Length; if (len == 0) throw new FormatException(Catalog.GetString("The string to parse is empty.")); //decide if it is hex, octal or decimal // if it starts with '0x' suppose it is hex if (i + 1 < len && trimStr[i] == '0' && trimStr[i+1] == 'x') return ConvertToNum(trimStr, i + 2, trimStr.Length - 1, 16); // if it starts with just '0' suppose it is octal if (i < len && trimStr[i] == '0') return ConvertToNum(trimStr, 8); // else suppose it is decimal return ConvertToNum(trimStr, 10); } } } // end namespace bless-0.6.3/src/util/ByteArray.cs000066400000000000000000000037571374060072200166420ustar00rootroot00000000000000// created on 1/13/2005 at 10:59 AM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.Text; using ByteList = System.Collections.Generic.List; namespace Bless.Util { ///Create byte arrays from various kinds of strings public class ByteArray { // Don't allow instantiation private ByteArray() { } static public byte[] FromString(string s, int baseNum) { int i = 0; int len = s.Length; ByteList ba = new ByteList(); // ignore leading whitespace while (i < len && s[i] == ' ') i++; while (i < len) { int k = 1; while (i + k < len && s[i+k] != ' ' && k < BaseConverter.DefaultMinDigits[baseNum]) k++; ba.Add((byte)BaseConverter.ConvertToNum(s, i, i + k - 1, baseNum)); // skip spaces i = i + k; while (i < len && s[i] == ' ') i++; } return ba.ToArray(); } static public string ToString(byte[] ba, int baseNum) { if (ba.Length == 0) return string.Empty; StringBuilder sb = new StringBuilder(ba.Length*(BaseConverter.DefaultMinDigits[baseNum] + 1)); foreach(byte b in ba) { sb.Append(BaseConverter.ConvertToString(b, baseNum)); sb.Append(' '); } return sb.ToString(0, sb.Length - 1); } } //end ByteArray } // end namespace bless-0.6.3/src/util/ConfigureDefines.cs.tmpl.in000066400000000000000000000026541374060072200215320ustar00rootroot00000000000000/* * Copyright (c) 2006, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ namespace Bless.Util { /// /// Useful constants defined by the configure script (taken from Banshee) /// public sealed class ConfigureDefines { public const string LOCALE_DIR = "@datadir@/locale/"; public const string PACKAGE = "@PACKAGE@"; public const string VERSION = "@VERSION@"; public const string GETTEXT_PACKAGE = "@GETTEXT_PACKAGE@"; public const string DATADIR = "@datadir@/@PACKAGE@/"; public const string HELPDIR = "@datadir@/help"; } } // end namespace bless-0.6.3/src/util/Deque.cs000066400000000000000000000050011374060072200157630ustar00rootroot00000000000000// created on 7/4/2005 at 12:24 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.Collections; using System.Collections.Generic; namespace Bless.Util { /// /// Double-ended queue data structure /// public class Deque: IEnumerable { Bless.Util.List list; public Deque() { list = new Bless.Util.List(); } /// /// Add an object to the front of the queue /// public void AddFront(T o) { list.InsertBefore(list.First, o); } public void AddEnd(T o) { list.InsertAfter(list.Last, o); } /// /// Remove an object from the front of the queue (LIFO) /// public T RemoveFront() { T o = default(T); if (list.First != null) { o = list.First.data; list.First.data = default(T); list.Remove(list.First); } return o; } /// /// Remove an object from the end of the queue (FIFO) /// public T RemoveEnd() { T o = default(T); if (list.Last != null) { o = list.Last.data; list.Last.data = default(T); list.Remove(list.Last); } return o; } /// /// Peek the object at the front of the queue /// public T PeekFront() { T o = default(T); if (list.First != null) o = list.First.data; return o; } /// /// Peek the object at the end of the queue /// public T PeekEnd() { T o = default(T); if (list.Last != null) o = list.Last.data; return o; } public void Clear() { while (Count > 0) RemoveFront(); } public int Count { get { return list.Count; } } public IEnumerator GetEnumerator() { return list.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } } // end namespacebless-0.6.3/src/util/FileResourcePath.cs000066400000000000000000000063271374060072200201400ustar00rootroot00000000000000// created on 3/11/2005 at 12:42 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System.Reflection; using System.IO; using System; namespace Bless.Util { ///Path of a file resource public class FileResourcePath { private FileResourcePath() { } private static string dataPath = null; /// /// Gets the full path of a file resource /// which is given relatively to the /// assembly path /// public static string GetBinPath(params string[] dirs) { // Get assembly path string assemblyPath = Assembly.GetCallingAssembly().Location; // Get assembly dir string assemblyDir = Path.GetDirectoryName(assemblyPath); string resourcePath = assemblyDir; foreach (string s in dirs) resourcePath = Path.Combine(resourcePath, s); return resourcePath; } /// /// Gets the full path of a file resource /// located in the Bless data directory /// public static string GetDataPath(params string[] dirs) { if (dataPath == null) { // get the local data path (eg when running bless from within the build directory) string localDataDir = GetBinPath("..", "..", "data"); // if the local data path exists and is valid use it // else try to use the installation data path if (Directory.Exists(localDataDir) && File.Exists(Path.Combine(localDataDir, "bless-default.layout"))) dataPath = localDataDir; else if (Directory.Exists(ConfigureDefines.DATADIR) && File.Exists(Path.Combine(ConfigureDefines.DATADIR, "bless-default.layout"))) dataPath = ConfigureDefines.DATADIR; else throw new DirectoryNotFoundException(localDataDir + " or " + ConfigureDefines.DATADIR); } string resourcePath = dataPath; foreach (string s in dirs) resourcePath = Path.Combine(resourcePath, s); return resourcePath; } public static string GetUserPath(params string[] dirs) { string resourcePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "bless"); foreach (string s in dirs) resourcePath = Path.Combine(resourcePath, s); return resourcePath; } public static string GetHelpDir() { string localHelpDir = GetDataPath("..", "doc", "user", "C"); string helpDir = ""; if (Directory.Exists(localHelpDir) && File.Exists(Path.Combine(localHelpDir, "index.docbook"))) { helpDir = localHelpDir; } else { helpDir = Path.Combine(ConfigureDefines.HELPDIR, "C", "bless"); } return helpDir; } } } // end namespace bless-0.6.3/src/util/IntervalTree.cs000066400000000000000000000073651374060072200173430ustar00rootroot00000000000000// Created 1:14 PM 16/3/2008 /* * Copyright (c) 2008, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.Collections.Generic; namespace Bless.Util { public class IntervalTree : RedBlackTree where T : IRange { protected class ITNode : INode { private long max; private long key; private IList values; private INode left, right; private Color color; public long Max { get { return max; } set { max = value; } } public long Key { get { return key; } set { key = value; } } public IList Values { get { return values; } set { values = value; UpdateMax();} } public INode Left { get { return left; } set { left = value; UpdateMax();} } public INode Right { get { return right; } set { right = value; UpdateMax();} } public Color Color { get { return color; } set { color = value; } } public ITNode(long key, T val, Color color) { this.key = key; this.values = new System.Collections.Generic.List(); this.values.Add(val); this.color = color; max = val.End; } private void UpdateMax() { long tmpMax = -1; if (this.Left != null) tmpMax = Math.Max(tmpMax, (this.Left as ITNode).Max); if (this.Right != null) tmpMax = Math.Max(tmpMax, (this.Right as ITNode).Max); foreach(T r in this.Values) { tmpMax = Math.Max(tmpMax, r.End); } this.max = tmpMax; } } protected class ITNodeFactory : INodeFactory { public INode CreateNode(long key, T val, Color color) { return new ITNode(key, val, color); } } private System.Collections.Generic.List searchResults; public IntervalTree() : base(new ITNodeFactory()) { } private bool RangesOverlap(IRange r1, IRange r2) { if (r1.Start >= r2.Start && r1.Start <= r2.End) return true; if (r1.End >= r2.Start && r1.End <= r2.End) return true; if (r1.Start <= r2.Start && r1.End >= r2.End) return true; return false; } protected override void AddToValues(INode n, T val) { base.AddToValues(n, val); (n as ITNode).Max = Math.Max((n as ITNode).Max, val.End); } public void Insert(T r) { Insert(r.Start, r); } public IList SearchOverlap(IRange r) { lock(lockObj) { searchResults = new System.Collections.Generic.List(); SearchOverlap(root as ITNode, r); return searchResults; } } private void SearchOverlap(ITNode n, IRange r) { // search in left subtree first, so that results are sorted if (n != null) { if (n.Max >= r.Start) { if(n.Left != null) SearchOverlap(n.Left as ITNode, r); foreach(T q in n.Values) { if (RangesOverlap(q, r)) searchResults.Add(q); } } if (n.Key <= r.End && n.Right != null) SearchOverlap(n.Right as ITNode, r); } } public void Delete(T r) { ITNode n = (this.SearchNode(r.Start) as ITNode); if (n == null) return; n.Values.Remove(r); if (n.Values.Count == 0) this.Delete(r.Start); } } } //end namespace bless-0.6.3/src/util/List.cs000066400000000000000000000066141374060072200156460ustar00rootroot00000000000000/* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.Collections; using System.Collections.Generic; namespace Bless.Util { ///A double-linked list public class List : IEnumerable { ///A node of the list public class Node { public T data; public Node next; public Node prev; public Node(T d, Node p, Node n) { data = d; prev = p; next = n; } } Node m_first; Node m_last; int m_count; public List() { m_first = null; m_last = null; } private Node AddFirst(T o) { m_first = new Node(o, null, null); m_last = m_first; ++m_count; return m_first; } ///Append an object to the list public Node Append(T o) { return InsertAfter(m_last, o); } ///Insert an object before a node in the list public Node InsertBefore(Node n, T o) { if (m_last == null) { // first entry? return AddFirst(o); } else { Node tmp = new Node(o, n.prev, n); if (n.prev != null) n.prev.next = tmp; n.prev = tmp; if (ReferenceEquals(n, m_first)) m_first = tmp; ++m_count; return tmp; } } ///Insert an object after a node in the list public Node InsertAfter(Node n, T o) { if (m_last == null) { // first entry? return AddFirst(o); } else { Node tmp = new Node(o, n, n.next); if (n.next != null) n.next.prev = tmp; n.next = tmp; if (ReferenceEquals(n, m_last)) m_last = tmp; ++m_count; return tmp; } } ///Remove a node (unlink it) public void Remove(Node n) { if (n.prev != null) n.prev.next = n.next; if (n.next != null) n.next.prev = n.prev; if (ReferenceEquals(n, m_first)) m_first = n.next; if (ReferenceEquals(n, m_last)) m_last = n.prev; n.next = null; n.prev = null; --m_count; } public T this[int index] { get { //Console.WriteLine("Asking for index {0}", index); if (index > m_count) return default(T); Node n = m_first; for (int i = 0; i < index; i++) n = n.next; return n.data; } } public IEnumerator GetEnumerator() { Node currentNode = First; while (currentNode != null) { yield return currentNode.data; currentNode = currentNode.next; } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public void Display() { Node n = m_first; while (n != null) { Console.Write("{0}<=>", n.data); n = n.next; } Console.WriteLine(); } public Node First { get { return m_first; } } public Node Last { get { return m_last; } } public int Count { get { return m_count; } } } } // end namespace bless-0.6.3/src/util/Portable.cs000066400000000000000000000035311374060072200164760ustar00rootroot00000000000000/* * Copyright (c) 2008, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using Mono.Unix.Native; using System; using System.Runtime.InteropServices; public class Portable { public static long GetAvailableMemory() { #if ENABLE_UNIX_SPECIFIC long availPages = Syscall.sysconf(SysconfName._SC_AVPHYS_PAGES); long pageSize = Syscall.sysconf(SysconfName._SC_PAGESIZE); long freeMem = availPages * pageSize; return freeMem; #else throw new NotImplementedException(); #endif } public static long GetAvailableDiskSpace(string path) { #if ENABLE_UNIX_SPECIFIC // get info about the device the file will be saved on Mono.Unix.Native.Statvfs stat = new Mono.Unix.Native.Statvfs(); Mono.Unix.Native.Syscall.statvfs(path, out stat); long freeSpace = (long)(stat.f_bavail * stat.f_bsize); return freeSpace; #else throw new NotImplementedException(); #endif } [DllImport("libfontconfig.so.1", CharSet = CharSet.Auto)] static extern IntPtr FcConfigAppFontAddFile(IntPtr fc, String path); public static void AddLocalFontFile(String path) { FcConfigAppFontAddFile(IntPtr.Zero, path); } } bless-0.6.3/src/util/ProgressCallback.cs000066400000000000000000000020301374060072200201400ustar00rootroot00000000000000// created on 3/29/2005 at 5:49 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ namespace Bless.Util { public enum ProgressAction { Show, Hide, Update, Message, Details, Destroy} public delegate bool ProgressCallback(object o, ProgressAction action); } bless-0.6.3/src/util/Range.cs000066400000000000000000000115621374060072200157650ustar00rootroot00000000000000// created on 10/25/2004 at 9:32 AM /* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; namespace Bless.Util { public interface IRange { long Start { get; set; } long End { get; set; } long Size { get; } bool IsEmpty(); void Clear(); } ///Represents a range of values public class Range : IRange, IEquatable { protected long start; protected long end; public long Start { get { return start; } set { start = value; } } public long End { get { return end; } set { end = value; } } public long Size { get { if (IsEmpty()) return 0; else if (end >= start) return end -start + 1; else return start -end + 1; } } public Range() { Clear(); } public Range(long s, long e) { start = s; end = e; } ///copy constructor public Range(IRange r): this(r.Start, r.End) { } ///value equality test public bool Equals(Range r) { return ((start == r.Start) && (end == r.End) || (end == r.Start) && (start == r.End)); } ///value equality test (for general objects) public override bool Equals(object obj) { Range r = obj as Range; if (r != null) return Equals(r); else return false; } // we should override GetHashCode() because we // are overriding Equals() public override int GetHashCode() { return (start.GetHashCode() ^ end.GetHashCode()); } public void Clear() { start = -1; end = -1; } public bool Contains(long n) { if (start < end) return (n >= start && n <= end); else return (n <= start && n >= end); } ///Evaluates the intersection of two ranges // NOTE: expects both ranges to be sorted public void Intersect(Range sel) { if (sel.Start >= start && sel.Start <= end) { start = sel.Start; if (sel.End < end) end = sel.End; } else if (sel.Start < start && sel.End >= start) { if (sel.End < end) end = sel.End; } else Clear(); } ///Evaluates the difference of two ranges. // NOTE: expects both ranges to be sorted public void Difference(Range r, Range r1) { if (r.Start > start && r.Start <= end) { if (r.End >= end) { end = r.Start - 1; r1.Clear(); } else { r1.Start = r.End + 1; r1.End = end; end = r.Start - 1; } } else if (r.Start <= start && r.End >= start) { r1.Clear(); if (r.End < end) start = r.End + 1; else Clear(); } } public bool IsEmpty() { return ((start == -1) && (end == -1)); } static public void SplitAtomic(Range[] results, Range r, Range s) { if (r.Contains(s.Start)) { results[0].Start = r.Start; results[0].End = s.Start - 1; results[1].Start = s.Start; results[1].End = s.End; if (r.Contains(s.End)) { results[2].Start = s.End + 1; results[2].End = r.End; } else { results[2].Clear(); } } else if (r.Contains(s.End)) { results[0].Clear(); results[1].Start = s.Start; results[1].End = s.End; results[2].Start = s.End + 1; results[2].End = r.End; } else if (s.Start < r.Start && s.End > r.End) { results[0].Clear(); results[1].Start = s.Start; results[1].End = s.End; results[2].Clear(); } else { if (r.Start < s.Start) { results[0].Start = r.Start; results[0].End = r.End; results[2].Clear(); } else { results[2].Start = r.Start; results[2].End = r.End; results[1].Clear(); } results[1].Start = s.Start; results[1].End = s.End; } foreach(Range result in results) { if (result.Start > result.End) result.Clear(); } } public bool Overlaps(IRange r) { if (r.Start >= Start && r.Start <= End) return true; if (r.End >= Start && r.End <= End) return true; if (r.Start <= Start && r.End >= End) return true; return false; } ///Make sure range start is less or equal to end public void Sort() { if (end < start) { long t = start; start = end; end = t; } } public override string ToString() { return string.Format("{0} -> {1}", start, end); } } } // end namespace bless-0.6.3/src/util/RangeCollection.cs000066400000000000000000000024521374060072200177770ustar00rootroot00000000000000// created on 8/25/2005 at 11:21 AM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System.Collections; namespace Bless.Util { public class RangeCollection: ArrayList { public Range LastAdded { get { return (Range)this[Count-1]; } } public RangeCollection() { Add(new Range()); } public void UpdateRange(Range oldRange, Range newRange) { int index = IndexOf(oldRange); RemoveAt(index); Insert(index, newRange); } public new void Clear() { base.Clear(); Add(new Range()); } } } // end namespace bless-0.6.3/src/util/RedBlackTree.cs000066400000000000000000000225061374060072200172200ustar00rootroot00000000000000/* * Copyright (c) 2008, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.Collections.Generic; using System.IO; using System.Text; namespace Bless.Util { /// /// A (left-leaning) red black tree (see [Sedgewick 2008]). /// Duplicates keys are all stored in the same node. /// public class RedBlackTree where K:IComparable { protected enum Color {Red, Black} private INodeFactory nodeFactory; protected INode root; protected object lockObj = new object(); private IList tmpValues; protected interface INode { K Key { get; set; } IList Values { get; set;} INode Left { get; set;} INode Right { get; set;} Color Color { get; set;} } protected interface INodeFactory { INode CreateNode(K key, V val, Color color); } protected class NodeFactory : INodeFactory { public INode CreateNode(K key, V val, Color color) { return new Node(key, val, color); } } protected class Node : INode { private K key; private IList values; private INode left, right; private Color color; public K Key { get { return key; } set { key = value; } } public IList Values { get { return values; } set { values = value; } } public INode Left { get { return left; } set { left = value; } } public INode Right { get { return right; } set { right = value; } } public Color Color { get { return color; } set { color = value; } } public Node(K key, V val, Color color) { this.key = key; this.values = new System.Collections.Generic.List(); this.values.Add(val); this.color = color; } } private bool IsRed(INode n) { if (n == null) return false; return (n.Color == Color.Red); } protected virtual INode RotL(INode h) { INode x = h.Right; h.Right = x.Left; x.Left = h; return x; } protected virtual INode RotR(INode h) { INode x = h.Left; h.Left = x.Right; x.Right = h; return x; } protected virtual INode SplitFourNode(INode h) { INode x = RotR(h); x.Left.Color = Color.Black; return x; } protected virtual INode LeanLeft(INode h) { INode x = RotL(h); x.Color = x.Left.Color; x.Left.Color = Color.Red; return x; } protected virtual INode LeanRight(INode h) { INode x = RotR(h); x.Color = x.Right.Color; x.Right.Color = Color.Red; return x; } protected INode MoveRedLeft(INode h) { h.Color = Color.Black; h.Left.Color = Color.Red; if (IsRed(h.Right.Left)) { h.Right = RotR(h.Right); h = RotL(h); } else h.Right.Color = Color.Red; return h; } protected INode MoveRedRight(INode h) { h.Color = Color.Black; h.Right.Color = Color.Red; if (IsRed(h.Left.Left)) { h = RotR(h); h.Color = Color.Red; h.Left.Color = Color.Black; } else h.Left.Color = Color.Red; return h; } private INode DeleteMin(INode h) { // remove node on bottom level (h must be RED by invariant) if (h.Left == null) return null; // push red link down if necessary if (!IsRed(h.Left) && !IsRed(h.Left.Left)) h = MoveRedLeft(h); // move down one level h.Left = DeleteMin(h.Left); // fix right-leaning red links on the way up the tree if (IsRed(h.Right)) h = LeanLeft(h); return h; } private INode FindMinNode(INode h) { while (h.Left != null) h = h.Left; return h; } protected virtual void AddToValues(INode n, V val) { n.Values.Add(val); } public RedBlackTree() { nodeFactory = new NodeFactory(); } protected RedBlackTree(INodeFactory nf) { nodeFactory = nf; } private INode Insert(INode h, K key, V val) { if (h == null) return nodeFactory.CreateNode(key, val, Color.Red); // split 4-nodes on the way down if (IsRed(h.Left) && IsRed(h.Left.Left)) h = SplitFourNode(h); // standard BST insert code int cmp = key.CompareTo(h.Key); if (cmp == 0) AddToValues(h, val); else if (cmp < 0) h.Left = Insert(h.Left, key, val); else h.Right = Insert(h.Right, key, val); // fix right-leaning reds on the way up if (IsRed(h.Right)) h = LeanLeft(h); return h; } /// /// Insert a key and its associated value into the tree. /// /// /// A /// /// /// A /// public virtual void Insert(K key, V val) { lock(lockObj) { root = Insert(root, key, val); root.Color = Color.Black; } } /// /// Search for the tree node that contains a key. /// /// /// A /// /// /// A /// protected virtual INode SearchNode(K key) { INode x = root; while (x != null) { int cmp = key.CompareTo(x.Key); if (cmp == 0) return x; else if (cmp < 0) x = x.Left; else if (cmp > 0) x = x.Right; } return null; } /// /// Search for all the values associated with a key. /// /// /// A /// /// /// A /// public virtual IList Search(K key) { lock(lockObj) { INode x = SearchNode(key); if (x != null) return x.Values; else return new System.Collections.Generic.List(0); } } private INode Delete(INode h, K key) { if (h == null) return null; int cmp = key.CompareTo(h.Key); if (cmp < 0) { // left // push red right if necessary if (!IsRed(h.Left) && h.Left != null && !IsRed(h.Left.Left)) h = MoveRedLeft(h); // move down (left) h.Left = Delete(h.Left, key); } else { // right or equal // rotate to push red right if (IsRed(h.Left)) { h = LeanRight(h); // LeanRight always rotates and brings (old) h to the right cmp = 1; } // equal (at bottom)... delete node // or search reached bottom and we must go right (cmp == 1) // but we can't (h.Right == null) -> the key is not in the tree if ((cmp == 0 || cmp == 1) && (h.Right == null)) return null; // push red right if necessary if (!IsRed(h.Right) && !IsRed(h.Right.Left)) { h = MoveRedRight(h); // MoveRedRight may or may not rotate so we must // check new node again cmp = key.CompareTo(h.Key); } // equal (not at bottom) if (cmp == 0) { INode minNode = FindMinNode(h.Right); // replace current node with successor key, value h.Key = minNode.Key; h.Values = minNode.Values; // delete successor h.Right = DeleteMin(h.Right); } else { // move down (right) h.Right = Delete(h.Right, key); } } // Fix right-leaning red links on the way up the tree if (IsRed(h.Right)) h = LeanLeft(h); return h; } /// /// Delete a key and all its associated values from the tree. /// /// /// A /// public virtual void Delete(K key) { lock(lockObj) { root = Delete(root, key); if (root != null) root.Color = Color.Black; } } /// /// Dump the contents of the tree as a graphviz/dot file /// /// /// A /// /// /// The title of the produced graph /// public void DumpToDot(string filename, string title) { lock(lockObj) { StringBuilder sb = new StringBuilder("digraph {\nlabel=\""+title+"\"\n"); DumpToDotInternal(root, sb); sb.Append("}\n"); StreamWriter sw = new StreamWriter(filename); sw.Write(sb.ToString()); sw.Close(); } } public void Clear() { lock (lockObj) { root = null; } } public IList GetValues() { lock (lockObj){ tmpValues = new System.Collections.Generic.List(); GetValues(root); // clear private var IList tv = tmpValues; tmpValues = null; return tv; } } private void GetValues(INode x) { if (x == null) return; GetValues(x.Left); foreach(V v in x.Values) tmpValues.Add(v); GetValues(x.Right); } private void DumpToDotInternal(INode h, StringBuilder sb) { if (h == null) return; DumpToDotInternal(h.Left, sb); if (h.Left != null) { string col = " [label=L, color=" + (h.Left.Color == Color.Red?"red, style=bold]\n":"black]"); sb.Append(h.Key + " -> " + h.Left.Key + col +"\n"); } if (h.Right != null) { string col = " [label=R, color=" + (h.Right.Color == Color.Red?"red, style=bold]\n":"black]"); sb.Append(h.Key + " -> " + h.Right.Key + col + "\n"); } DumpToDotInternal(h.Right, sb); } } } // end namespacebless-0.6.3/src/util/TempFile.cs000066400000000000000000000026121374060072200164320ustar00rootroot00000000000000// created on 10/27/2004 at 3:13 PM /* * Copyright (c) 2004, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.IO; namespace Bless.Util { public class TempFile { private TempFile() { } static public string CreateName(string dir) { string str; Random rand = new Random(); do { str = string.Empty; for (int i = 0; i < 8; i++) { str += Convert.ToChar(rand.Next() % 26 + Convert.ToInt32('a')); } } while (File.Exists(dir + Path.DirectorySeparatorChar + str + ".bless") == true); //System.Console.WriteLine("Created random: {0}",str); return Path.Combine(dir, str + ".bless"); } } }//end namespace bless-0.6.3/src/util/ThreadedAsyncOperation.cs000066400000000000000000000116361374060072200213320ustar00rootroot00000000000000// created on 4/4/2005 at 4:20 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.Threading; namespace Bless.Util { /// /// Abstract class modelling a threaded asynchronous operation /// public abstract class ThreadedAsyncOperation { protected bool cancelled; protected ProgressCallback progressCallback; protected AsyncCallback opFinishedCallback; protected bool activateProgress; Exception threadException; OperationResult opResult; bool useGLibIdle; Timer showProgressTimer; Timer progressTimer; // the kind of event that the save thread can emit to // the main thread private enum Event { ShowProgress, Finished, Exception} // the result of the operation public enum OperationResult { Finished, Cancelled, CaughtException } public OperationResult Result { get { return opResult; } set { opResult = value; } } public Exception ThreadException { get { return threadException; } set { threadException = value;} } public ThreadedAsyncOperation(ProgressCallback pc, AsyncCallback ac, bool glibIdle) { progressCallback = pc; opFinishedCallback = ac; useGLibIdle = glibIdle; cancelled = false; activateProgress = true; // showProgressTimer fires once and makes progress reporting visible showProgressTimer = new Timer(new TimerCallback(ShowProgressTimerExpired), null, Timeout.Infinite, Timeout.Infinite); // progressTimer fires periodically and updates progress reporting progressTimer = new Timer(new TimerCallback(ProgressTimerExpired), null, Timeout.Infinite, Timeout.Infinite); } protected abstract bool StartProgress(); protected abstract bool UpdateProgress(); protected abstract bool EndProgress(); protected abstract void DoOperation(); protected abstract void EndOperation(); /// /// Called when the operation has finished /// void OperationFinished() { // destroy progress report if (progressCallback != null) EndProgress(); // call callback if (opFinishedCallback != null) opFinishedCallback(new ThreadedAsyncResult(this, null, true)); } /// /// Called once by a timer to make the progress report visible /// void ShowProgressTimerExpired(object o) { if (progressCallback != null) { if (useGLibIdle) GLib.Idle.Add(StartProgress); else StartProgress(); } } /// /// Called periodically by a timer to update the progress report /// void ProgressTimerExpired(object o) { if (progressCallback != null) { if (useGLibIdle) GLib.Idle.Add(delegate { cancelled = UpdateProgress(); return false; }); else cancelled = UpdateProgress(); } } protected void ActivateProgressReport(bool activate) { try { if (activate) { progressTimer.Change(0, 50); showProgressTimer.Change(500, 0); } else { progressTimer.Change(Timeout.Infinite, Timeout.Infinite); showProgressTimer.Change(Timeout.Infinite, Timeout.Infinite); } } catch(ObjectDisposedException) {} } public void OperationThread() { ActivateProgressReport(activateProgress); try { DoOperation(); if (cancelled) opResult = OperationResult.Cancelled; else opResult = OperationResult.Finished; } catch (Exception e) { threadException = e; opResult = OperationResult.CaughtException; } finally { progressTimer.Dispose(); showProgressTimer.Dispose(); EndOperation(); if (useGLibIdle) GLib.Idle.Add(delegate { OperationFinished(); return false; }); else OperationFinished(); } } } /// /// Class to hold information about an asynchronous threaded operation /// public class ThreadedAsyncResult: IAsyncResult { object asyncState; WaitHandle asyncWaitHandle; bool isCompleted; public ThreadedAsyncResult(object state, WaitHandle handle, bool complete) { asyncState = state; asyncWaitHandle = handle; isCompleted = complete; } public object AsyncState { get { return asyncState;} } public WaitHandle AsyncWaitHandle { get { return asyncWaitHandle;} } public bool CompletedSynchronously { get { return false;} } public bool IsCompleted { get { return isCompleted;} } } } // end namespace bless-0.6.3/tests/000077500000000000000000000000001374060072200137735ustar00rootroot00000000000000bless-0.6.3/tests/buffers/000077500000000000000000000000001374060072200154275ustar00rootroot00000000000000bless-0.6.3/tests/buffers/ByteBufferTests.cs000066400000000000000000000217671374060072200210530ustar00rootroot00000000000000// created on 3/8/2005 at 5:02 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using NUnit.Framework; using System; using System.Threading; using Bless.Buffers; namespace BlessTests.Buffers { [TestFixture] public class ByteBufferTests { [Test] public void AppendDoTest() { ByteBuffer bb = new ByteBuffer(); byte[] ba = {1, 3, 5, 7, 13, 17}; bb.Append(ba, 0, ba.LongLength); Assert.AreEqual(6, bb.Size); Assert.AreEqual(1, bb[0]); Assert.AreEqual(3, bb[1]); Assert.AreEqual(5, bb[2]); Assert.AreEqual(7, bb[3]); Assert.AreEqual(13, bb[4]); Assert.AreEqual(17, bb[5]); } [Test] public void AppendUndoTest() { ByteBuffer bb = new ByteBuffer(); byte[] ba = {1, 3, 5, 7}; byte[] ba1 = {13, 17}; bb.Append(ba, 0, ba.LongLength); bb.Append(ba1, 0, ba1.LongLength); Assert.AreEqual(6, bb.Size, "#1"); Assert.AreEqual(3, bb[1], "#2"); Assert.AreEqual(17, bb[5], "#3"); bb.Undo(); Assert.AreEqual(4, bb.Size, "#4"); Assert.AreEqual(1, bb[0], "#5"); Assert.AreEqual(3, bb[1], "#6"); Assert.AreEqual(5, bb[2], "#7"); Assert.AreEqual(7, bb[3], "#8"); } [Test] public void InsertDoTest() { ByteBuffer bb = new ByteBuffer(); byte[] ba = {1, 3, 17}; byte[] ba1 = {5, 7, 13}; bb.Append(ba, 0, ba.LongLength); //bb.Display("D1"); bb.Insert(2, ba1, 0, ba1.LongLength); //bb.Display("D2"); Assert.AreEqual(6, bb.Size, "#1"); Assert.AreEqual(1, bb[0], "#2"); Assert.AreEqual(3, bb[1], "#3"); Assert.AreEqual(5, bb[2], "#4"); Assert.AreEqual(7, bb[3], "#5"); Assert.AreEqual(13, bb[4], "#6"); Assert.AreEqual(17, bb[5], "#7"); } [Test] public void InsertUndoTest() { ByteBuffer bb = new ByteBuffer(); byte[] ba = {1, 3, 17}; byte[] ba1 = {5, 7, 13}; bb.Append(ba, 0, ba.LongLength); //bb.Display("D1"); bb.Insert(2, ba1, 0, ba1.LongLength); //bb.Display("D2"); Assert.AreEqual(6, bb.Size, "#1"); Assert.AreEqual(3, bb[1], "#2"); Assert.AreEqual(17, bb[5], "#3"); bb.Undo(); //bb.Display("D3"); Assert.AreEqual(3, bb.Size, "#4"); Assert.AreEqual(1, bb[0], "#5"); Assert.AreEqual(3, bb[1], "#6"); Assert.AreEqual(17, bb[2], "#7"); } [Test] public void DeleteDoTest() { ByteBuffer bb = new ByteBuffer(); byte[] ba = {1, 3, 17}; byte[] ba1 = {5, 7, 13}; bb.Append(ba, 0, ba.LongLength); //bb.Display("D1"); bb.Insert(2, ba1, 0, ba1.LongLength); //bb.Display("D2"); bb.Delete(1, 3); Assert.AreEqual(3, bb.Size, "#1"); Assert.AreEqual(1, bb[0], "#2"); Assert.AreEqual(13, bb[1], "#3"); Assert.AreEqual(17, bb[2], "#4"); } [Test] public void DeleteUndoTest() { ByteBuffer bb = new ByteBuffer(); byte[] ba = {1, 3, 17}; byte[] ba1 = {5, 7, 13}; bb.Append(ba, 0, ba.LongLength); //bb.Display("D1"); bb.Insert(2, ba1, 0, ba1.LongLength); //bb.Display("D2"); bb.Delete(1, 3); Assert.AreEqual(3, bb.Size, "#1"); Assert.AreEqual(1, bb[0], "#2"); Assert.AreEqual(13, bb[1], "#3"); Assert.AreEqual(17, bb[2], "#4"); bb.Undo(); Assert.AreEqual(6, bb.Size, "#5"); Assert.AreEqual(1, bb[0], "#6"); Assert.AreEqual(3, bb[1], "#7"); Assert.AreEqual(5, bb[2], "#8"); Assert.AreEqual(7, bb[3], "#9"); Assert.AreEqual(13, bb[4], "#10"); Assert.AreEqual(17, bb[5], "#11"); } [Test] public void FileLoadTest1() { ByteBuffer bb = ByteBuffer.FromFile("test1.bin"); long size = bb.Size; int sum = 0; for (int i = 0; i < size; i++) sum ^= bb[i]; Assert.AreEqual( 0x88, sum, "XOR Result"); } [Test] public void FileLoadTest2() { ByteBuffer bb = ByteBuffer.FromFile("test1.bin"); byte[] ba = {0x41, 0x61}; bb.Append(ba, 0, ba.LongLength); long size = bb.Size; int sum = 0; for (int i = 0; i < size; i++) sum ^= bb[i]; Assert.AreEqual( 0x88 ^ 0x20, sum); } [Test] public void FileLoadTest3() { ByteBuffer bb = ByteBuffer.FromFile("test1.bin"); byte[] ba = {0x41, 0x61}; bb.Insert(768, ba, 0, ba.LongLength); long size = bb.Size; int sum = 0; for (int i = 0; i < size; i++) sum ^= bb[i]; Assert.AreEqual( 0x88 ^ 0x20, sum); } [Test] [Ignore("It fails, perhaps because it is run from nunit")] public void FileSaveTest1() { ByteBuffer bb = ByteBuffer.FromFile("test1.bin"); byte[] ba = {0x41, 0x61}; long size1 = bb.Size; bb.Insert(768, ba, 0, ba.LongLength); Assert.AreEqual(size1 + 2, bb.Size, "#1"); IAsyncResult ar = bb.BeginSaveAs("test2.bin", null, null); ar.AsyncWaitHandle.WaitOne(); bb.CloseFile(); ByteBuffer bb1 = ByteBuffer.FromFile("test2.bin"); Assert.AreEqual(bb.Size, bb1.Size, "#2"); long size = bb1.Size; for (int i = 0; i < size; i++) { if (bb1[i] != bb[i]) Assert.Fail(string.Format("#3 Difference at {0} ({1}!={2})", i, bb1[i], bb[i])); } } [Test] public void HasChangedTest() { ByteBuffer bb = new ByteBuffer(); byte[] ba = {0x41, 0x61}; Assert.AreEqual(false, bb.HasChanged, "#0"); bb.Append(ba, 0, ba.LongLength); Assert.AreEqual(true, bb.HasChanged, "#1"); bb.Undo(); Assert.AreEqual(false, bb.HasChanged, "#2"); } [Test] public void InsertEmptyUndoTest() { ByteBuffer bb = new ByteBuffer(); byte[] ba = {0x01, 0x02, 0xfe, 0xff}; byte[] baEmpty = new byte[0]; bb.Append(ba, 0, ba.LongLength); bb.Insert(2, baEmpty, 0, baEmpty.LongLength); Assert.AreEqual(4, bb.Size, "#Size before undo"); Assert.AreEqual(0x01, bb[0], "#bb[0] before undo"); Assert.AreEqual(0x02, bb[1], "#bb[1] before undo"); Assert.AreEqual(0xfe, bb[2], "#bb[2] before undo"); Assert.AreEqual(0xff, bb[3], "#bb[3] before undo"); bb.Undo(); Assert.AreEqual(4, bb.Size, "#Size after undo"); Assert.AreEqual(0x01, bb[0], "#bb[0] after undo"); Assert.AreEqual(0x02, bb[1], "#bb[1] after undo"); Assert.AreEqual(0xfe, bb[2], "#bb[2] after undo"); Assert.AreEqual(0xff, bb[3], "#bb[3] after undo"); } [Test] public void AppendEmptyUndoTest() { ByteBuffer bb = new ByteBuffer(); byte[] ba = {0x01, 0x02, 0xfe, 0xff}; byte[] baEmpty = new byte[0]; bb.Append(ba, 0, ba.LongLength); bb.Append(baEmpty, 0, baEmpty.LongLength); Assert.AreEqual(4, bb.Size, "#Size before undo"); Assert.AreEqual(0x01, bb[0], "#bb[0] before undo"); Assert.AreEqual(0x02, bb[1], "#bb[1] before undo"); Assert.AreEqual(0xfe, bb[2], "#bb[2] before undo"); Assert.AreEqual(0xff, bb[3], "#bb[3] before undo"); bb.Undo(); Assert.AreEqual(4, bb.Size, "#Size after undo"); Assert.AreEqual(0x01, bb[0], "#bb[0] after undo"); Assert.AreEqual(0x02, bb[1], "#bb[1] after undo"); Assert.AreEqual(0xfe, bb[2], "#bb[2] after undo"); Assert.AreEqual(0xff, bb[3], "#bb[3] after undo"); } [Test] public void ActionChainingTest() { ByteBuffer bb = new ByteBuffer(); byte[] ba1 = {0x01, 0x04}; byte[] ba2 = {0x02, 0x03}; byte[] ba3 = {0x05, 0x06}; byte[] ba4 = {0x07, 0x08}; bb.BeginActionChaining(); bb.Append(ba1, 0, ba1.LongLength); bb.Insert(1, ba2, 0, ba2.LongLength); bb.EndActionChaining(); Assert.AreEqual(4, bb.Size, "#1"); Assert.IsTrue(bb.CanUndo, "#2"); bb.Undo(); Assert.AreEqual(0, bb.Size, "#3"); Assert.IsFalse(bb.CanUndo, "#4"); bb.Redo(); bb.BeginActionChaining(); bb.Append(ba4, 0, ba4.LongLength); bb.Insert(4, ba3, 0, ba3.LongLength); bb.EndActionChaining(); Assert.AreEqual(8, bb.Size, "#5"); Assert.IsTrue(bb.CanUndo, "#6"); bb.Undo(); Assert.AreEqual(4, bb.Size, "#7"); Assert.IsTrue(bb.CanUndo, "#8"); } [Test] public void LimitedUndoTest() { ByteBuffer bb = new ByteBuffer(); bb.MaxUndoActions = 3; byte[] ba1 = {0x01, 0x04}; byte[] ba2 = {0x02, 0x03}; byte[] ba3 = {0x05, 0x06}; byte[] ba4 = {0x07, 0x08}; bb.Append(ba1, 0, ba1.LongLength); bb.Insert(1, ba2, 0, ba2.LongLength); bb.Append(ba4, 0, ba4.LongLength); bb.Insert(4, ba3, 0, ba3.LongLength); Assert.AreEqual(true, bb.CanUndo, "#1"); bb.Undo(); Assert.AreEqual(true, bb.CanUndo, "#2"); bb.Undo(); Assert.AreEqual(true, bb.CanUndo, "#3"); bb.Undo(); Assert.AreEqual(false, bb.CanUndo, "#4"); Assert.AreEqual(2, bb.Size, "#5"); Assert.AreEqual(0x01, bb[0], "#6"); Assert.AreEqual(0x04, bb[1], "#7"); bb.Redo(); bb.Redo(); bb.Redo(); Assert.AreEqual(8, bb.Size, "#8"); bb.MaxUndoActions = 2; bb.Undo(); Assert.AreEqual(6, bb.Size, "#8.5"); Assert.AreEqual(true, bb.CanUndo, "#9"); bb.Undo(); Assert.AreEqual(false, bb.CanUndo, "#10"); Assert.AreEqual(4, bb.Size, "#11"); } } } // end namespace bless-0.6.3/tests/buffers/FileBufferTests.cs000066400000000000000000000031351374060072200210140ustar00rootroot00000000000000// created on 3/8/2005 at 5:11 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using NUnit.Framework; using System; using Bless.Buffers; namespace BlessTests.Buffers { [TestFixture] public class FileBufferTests { [Test] public void LoadFile() { FileBuffer fb = new FileBuffer("test1.bin"); byte[] baExpect = {0x3c, 0x13, 0xe3, 0x36, 0xcc, 0x66, 0x21, 0xda}; byte[] ba = new byte[baExpect.Length]; fb.Read(ba, 0, 0x3f0, baExpect.Length); Assert.IsNotNull(ba, "#1"); for (int i = 0;i < baExpect.Length;i++) Assert.AreEqual(baExpect[i], ba[i]); } [Test] public void IndexerAccessTest() { FileBuffer fb = new FileBuffer("test1.bin"); Assert.IsNotNull(fb, "#1"); long size = fb.Size; int sum = 0; for (int i = 0; i < size; i++) sum ^= fb[i]; Assert.AreEqual( 0x88, sum); } } } // end namespace bless-0.6.3/tests/buffers/SegmentCollectionTests.cs000066400000000000000000000236051374060072200224250ustar00rootroot00000000000000// created on 3/8/2005 at 5:15 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using NUnit.Framework; using System; using Bless.Util; using Bless.Buffers; namespace BlessTests.Buffers { [TestFixture] public class SegmentCollectionTests { Bless.Buffers.IBuffer buf1; Bless.Buffers.IBuffer buf2; [SetUp] public void Init() { buf1 = new BaseBuffer(); buf2 = new BaseBuffer(); } [Test] public void AppendSegmentsTest1() { SegmentCollection segs = new SegmentCollection(); Segment s1, s2; s1 = new Segment(buf1, 0, 5); s2 = new Segment(buf2, 6, 5); segs.Append(s1); segs.Append(s2); Assert.AreSame(s1, segs.List[0]); Assert.AreSame(s2, segs.List[1]); } [Test] public void AppendSegmentsTest2() { SegmentCollection segs = new SegmentCollection(); Segment s1, s2; s1 = new Segment(buf1, 0, 5); s2 = new Segment(buf1, 6, 8); segs.Append(s1); segs.Append(s2); Assert.AreSame(s1, segs.List[0]); Assert.IsTrue(s1.Start == 0); Assert.IsTrue(s1.End == 8); //Assert.IsNull(segs[1]); } [Test] public void FindSegmentTest() { SegmentCollection segs1 = new SegmentCollection(); Segment s1, s2, s3, s4; s1 = new Segment(buf1, 0, 5); s2 = new Segment(buf2, 6, 8); s3 = new Segment(buf2, 0, 5); s4 = new Segment(buf1, 6, 8); segs1.Append(s1); segs1.Append(s2); segs1.Append(s3); segs1.Append(s4); long map; List.Node n; Assert.AreSame(s1, segs1.FindSegment(4, out map, out n)); Assert.AreEqual(0, map); Assert.AreSame(s3, segs1.FindSegment(10, out map, out n)); Assert.AreEqual(9, map); } [Test] public void InsertSegmentCollectionTest1() { SegmentCollection segs1 = new SegmentCollection(); SegmentCollection segs2 = new SegmentCollection(); Segment s1, s2, s3, s4; s1 = new Segment(buf1, 0, 5); s2 = new Segment(buf2, 6, 8); s3 = new Segment(buf2, 0, 5); s4 = new Segment(buf1, 6, 8); segs1.Append(s1); segs1.Append(s2); segs2.Append(s3); segs2.Append(s4); segs1.Insert(segs2, 6); Assert.AreSame(s1, segs1.List[0]); Assert.AreSame(s3, segs1.List[1]); Assert.AreSame(s4, segs1.List[2]); Assert.AreSame(s2, segs1.List[3]); //Assert.IsNull(segs[1]); } [Test] public void InsertSegmentCollectionTest2() { SegmentCollection segs1 = new SegmentCollection(); SegmentCollection segs2 = new SegmentCollection(); Segment s1, s2, s3, s4; s1 = new Segment(buf1, 0, 5); s2 = new Segment(buf2, 6, 8); s3 = new Segment(buf2, 0, 5); s4 = new Segment(buf1, 6, 8); segs1.Append(s1); segs1.Append(s2); segs2.Append(s3); segs2.Append(s4); segs1.Insert(segs2, 4); Assert.IsTrue(s1.End == 3); Assert.AreSame(s1, segs1.List[0]); Assert.AreSame(s3, segs1.List[1]); Assert.AreSame(s4, segs1.List[2]); Assert.AreSame(s2, segs1.List[4]); Assert.IsTrue(((Segment)segs1.List[3]).Start == 4); Assert.IsTrue(((Segment)segs1.List[3]).Buffer == buf1); Assert.IsTrue(((Segment)segs1.List[3]).End == 5); //Assert.IsNull(segs[1]); } [Test] public void InsertSegmentCollectionAtEndTest() { SegmentCollection segs1 = new SegmentCollection(); SegmentCollection segs2 = new SegmentCollection(); Segment s1, s2, s3, s4; s1 = new Segment(buf1, 0, 5); s2 = new Segment(buf2, 6, 8); s3 = new Segment(buf2, 0, 5); s4 = new Segment(buf1, 6, 8); segs1.Append(s1); segs1.Append(s2); segs2.Append(s3); segs2.Append(s4); segs1.Insert(segs2, 9); Assert.AreSame(s1, segs1.List[0]); Assert.AreSame(s2, segs1.List[1]); Assert.AreSame(s3, segs1.List[2]); Assert.AreSame(s4, segs1.List[3]); //Assert.IsNull(segs[1]); } [Test] public void InsertSegmentCollectionThenFindTest() { SegmentCollection segs1 = new SegmentCollection(); SegmentCollection segs2 = new SegmentCollection(); Segment s1, s2, s3, s4; s1 = new Segment(buf1, 0, 5); s2 = new Segment(buf2, 6, 8); s3 = new Segment(buf2, 0, 5); s4 = new Segment(buf1, 6, 8); segs1.Append(s1); segs1.Append(s2); segs2.Append(s3); segs2.Append(s4); segs1.Insert(segs2, 4); long map; List.Node n; //segs1.List.Display(); Assert.AreSame(s1, segs1.FindSegment(3, out map, out n), "s1"); Assert.AreEqual(0, map); Assert.AreSame(s3, segs1.FindSegment(7, out map, out n), "s3"); Assert.AreEqual(4, map); Assert.AreSame(s4, segs1.FindSegment(12, out map, out n), "s4"); Assert.AreEqual(10, map); Segment s5 = segs1.FindSegment(13, out map, out n); Assert.AreEqual(13, map); Assert.IsTrue(s5.End == s5.Start + 1, "s1'"); Assert.AreSame(s2, segs1.FindSegment(15, out map, out n), "s2"); Assert.AreEqual(15, map); } [Test] public void DeleteFromSegmentCollectionTest1() { SegmentCollection segs1 = new SegmentCollection(); Segment s1, s2, s3, s4; s1 = new Segment(buf1, 0, 5); s2 = new Segment(buf2, 6, 8); s3 = new Segment(buf2, 0, 5); s4 = new Segment(buf1, 6, 8); segs1.Append(s1); segs1.Append(s2); segs1.Append(s3); segs1.Append(s4); segs1.DeleteRange(7, 15); Assert.AreEqual(3, segs1.List.Count, "#1"); Assert.AreEqual(6, ((Segment)segs1.List[0]).Size, "#2"); Assert.AreEqual(6, ((Segment)segs1.List[1]).Start, "#3"); Assert.AreEqual(6, ((Segment)segs1.List[1]).End, "#4"); Assert.AreEqual(7, ((Segment)segs1.List[2]).Start, "#5"); Assert.AreEqual(8, ((Segment)segs1.List[2]).End, "#6"); } [Test] public void DeleteFromSegmentCollectionTest2() { SegmentCollection segs1 = new SegmentCollection(); Segment s1; s1 = new Segment(buf1, 0, 8); segs1.Append(s1); SegmentCollection del = segs1.DeleteRange(3, 6); Assert.AreEqual(2, segs1.List.Count, "#0"); Assert.AreEqual(0, ((Segment)segs1.List[0]).Start, "#1"); Assert.AreEqual(2, ((Segment)segs1.List[0]).End, "#2"); Assert.AreEqual(7, ((Segment)segs1.List[1]).Start, "#3"); Assert.AreEqual(8, ((Segment)segs1.List[1]).End, "#4"); Assert.AreEqual(1, del.List.Count, "#5"); Assert.AreEqual(3, ((Segment)del.List[0]).Start, "#6"); Assert.AreEqual(6, ((Segment)del.List[0]).End, "#7"); } [Test] public void DeleteFromSegmentCollectionTest3() { SegmentCollection segs1 = new SegmentCollection(); Segment s1; s1 = new Segment(buf1, 0, 8); segs1.Append(s1); SegmentCollection del = segs1.DeleteRange(0, 6); Assert.AreEqual(1, segs1.List.Count, "#0"); Assert.AreEqual(7, ((Segment)segs1.List[0]).Start, "#1"); Assert.AreEqual(8, ((Segment)segs1.List[0]).End, "#2"); Assert.AreEqual(1, del.List.Count, "#5"); Assert.AreEqual(0, ((Segment)del.List[0]).Start, "#6"); Assert.AreEqual(6, ((Segment)del.List[0]).End, "#7"); } [Test] public void DeleteFromSegmentCollectionTest4() { SegmentCollection segs1 = new SegmentCollection(); Segment s1; s1 = new Segment(buf1, 0, 8); segs1.Append(s1); SegmentCollection del = segs1.DeleteRange(0, 8); Assert.AreEqual(0, segs1.List.Count, "#0"); Assert.AreEqual(1, del.List.Count, "#5"); Assert.AreEqual(0, ((Segment)del.List[0]).Start, "#6"); Assert.AreEqual(8, ((Segment)del.List[0]).End, "#7"); } [Test] public void DeleteFromSegmentCollectionTest5() { SegmentCollection segs1 = new SegmentCollection(); Segment s1; s1 = new Segment(buf1, 0, 8); segs1.Append(s1); SegmentCollection del = segs1.DeleteRange(6, 8); Assert.AreEqual(1, segs1.List.Count, "#0"); Assert.AreEqual(0, ((Segment)segs1.List[0]).Start, "#1"); Assert.AreEqual(5, ((Segment)segs1.List[0]).End, "#2"); Assert.AreEqual(1, del.List.Count, "#5"); Assert.AreEqual(6, ((Segment)del.List[0]).Start, "#6"); Assert.AreEqual(8, ((Segment)del.List[0]).End, "#7"); } [Test] public void InsertToSegmentCollectionThenDeleteTest() { SegmentCollection segs1 = new SegmentCollection(); Segment s1, s2; s1 = new Segment(buf1, 0, 2); s2 = new Segment(buf1, 3, 5); segs1.Append(s1); SegmentCollection segs2 = new SegmentCollection(); segs2.Append(s2); segs1.Insert(segs2, 2); segs1.DeleteRange(2, 4); long map; List.Node n; Segment s = segs1.FindSegment(0, out map, out n); Assert.IsNotNull(s, "#1"); Assert.AreEqual(0, map, "#2"); Assert.AreEqual(0, s.Start, "#3"); } [Test] public void ReplaceAtEnd() { SegmentCollection segs1 = new SegmentCollection(); Segment s1, s2, s3; s1 = new Segment(buf1, 0, 4); s2 = new Segment(buf2, 7, 7); s3 = new Segment(buf2, 8, 8); segs1.Append(s1); //segs1.List.Display(); segs1.DeleteRange(4, 4); //segs1.List.Display(); segs1.Append(s2); //segs1.List.Display(); segs1.DeleteRange(4, 4); //segs1.List.Display(); segs1.Append(s3); //segs1.List.Display(); Assert.AreEqual(2, segs1.List.Count, "#1"); Assert.AreEqual(3, (segs1.List[0] as Segment).End, "#2"); Assert.AreEqual(8, (segs1.List[1] as Segment).Start, "#3"); Assert.AreEqual(8, (segs1.List[1] as Segment).End, "#4"); } [Test] public void InsertInEmptyCollection() { SegmentCollection segs1 = new SegmentCollection(); SegmentCollection segs2 = new SegmentCollection(); Segment s1 = new Segment(buf1, 0, 4); Segment s2 = new Segment(buf2, 7, 9); segs2.Append(s1); segs2.Append(s2); segs1.Insert(segs2, 0); Assert.AreEqual(2, segs1.List.Count, "#1"); Assert.AreEqual(4, (segs1.List[0] as Segment).End, "#2"); Assert.AreEqual(7, (segs1.List[1] as Segment).Start, "#3"); Assert.AreEqual(9, (segs1.List[1] as Segment).End, "#4"); } } } // end namespace bless-0.6.3/tests/buffers/SegmentTests.cs000066400000000000000000000027461374060072200204140ustar00rootroot00000000000000// created on 3/8/2005 at 5:14 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using NUnit.Framework; using System; using Bless.Buffers; namespace BlessTests.Buffers { [TestFixture] public class SegmentTests { [Test] public void SplitTest1() { Segment s = new Segment(null, 3, 8); Segment s1 = s.SplitAt(3); Assert.AreEqual(3, s.Start); Assert.AreEqual(5, s.End); Assert.AreEqual(6, s1.Start); Assert.AreEqual(8, s1.End); } [Test] public void SplitTest2() { Segment s = new Segment(null, 3, 8); Segment s1 = s.SplitAt(0); Assert.IsNull(s1); } [Test] public void ToStringTest() { Segment s = new Segment(null, 3, 8); Assert.AreEqual("(3->8)", s.ToString()); } } } // end namespacebless-0.6.3/tests/buffers/SimpleBufferTests.cs000066400000000000000000000031041374060072200213620ustar00rootroot00000000000000// created on 3/8/2005 at 5:07 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using NUnit.Framework; using System; using Bless.Buffers; namespace BlessTests.Buffers { [TestFixture] public class SimpleBufferTests { [Test] public void AppendTest() { SimpleBuffer sb = new SimpleBuffer(); byte[] ba = {1, 2, 3}; sb.Append(ba, 0, ba.Length); Assert.AreEqual(1, sb[0]); Assert.AreEqual(2, sb[1]); Assert.AreEqual(3, sb[2]); Assert.AreEqual(0, sb[3]); } [Test] public void ReadTest() { SimpleBuffer sb = new SimpleBuffer(); byte[] ba = {1, 2, 3, 4, 5}; sb.Append(ba, 0, ba.Length); byte[] ba1 = new byte[3]; sb.Read(ba1, 0, 1, 3); Assert.AreEqual(3, ba1.Length); Assert.AreEqual(2, ba1[0]); Assert.AreEqual(3, ba1[1]); Assert.AreEqual(4, ba1[2]); } } } // end namespace bless-0.6.3/tests/buffers/test1.bin000066400000000000000000000020001374060072200171510ustar00rootroot00000000000000i80tn[XFt "4LG%bJ*$ D11"ڲgZéOJ)Q*dTB%r^jquJf٤ޞXށEbkpPN<?bw X~= P>c81jkڌ膒%=>ΘUo lbR`L2UAsNQZV *b p !vT.'sәllD;"᛹Yq>he5nԖÇx,[ZPFveHVDQ?xש35xu=i (sBGr@nCH)7dh#\VIc U;q]Spj eƕ|NJv8lSnL>RH*&3ՈҜxJ(k)\/[r!//; !&e Ѹ$@><6f!ڬ+Lfbless-0.6.3/tests/copy_test_data.py000077500000000000000000000002061374060072200173500ustar00rootroot00000000000000#!/usr/bin/env python3 import sys import shutil shutil.copyfile(sys.argv[1], sys.argv[2]) shutil.copymode(sys.argv[1], sys.argv[2]) bless-0.6.3/tests/meson.build000066400000000000000000000044041374060072200161370ustar00rootroot00000000000000nunit_console = find_program('nunit-console', required: false) nunit_dep = dependency('nunit', required: false) if not nunit_dep.found() error('nunit not found, cannot build tests. You can disable with -Dtests=false') endif test_env = environment() test_env.append('MONO_PATH', src_build_dir) tests_buffers_lib = library( 'BlessTests.Buffers', files( 'buffers/ByteBufferTests.cs', 'buffers/FileBufferTests.cs', 'buffers/SegmentCollectionTests.cs', 'buffers/SegmentTests.cs', 'buffers/SimpleBufferTests.cs', ), dependencies: nunit_dep, link_with: [ buffers_lib, util_lib, ], ) # The tests expect the test data files to be in the directory the runner runs in. # nunit-console changes directory to the module under test before running, # so copy the data files to that same build directory. meson.add_postconf_script( 'copy_test_data.py', join_paths(meson.current_source_dir(), 'buffers', 'test1.bin'), join_paths(meson.current_build_dir(), 'test1.bin')) if get_option('run_tests') if not nunit_console.found() warning('nunit-console not found, cannot run tests. You can disable with -Drun_tests=false') subdir_done() endif test( 'Buffers', nunit_console, args: tests_buffers_lib, env: test_env, ) tests_tools_export_lib = library( 'BlessTests.Tools.Export', files( 'tools/export/ExporterTests.cs', ), dependencies: nunit_dep, link_with: [ buffers_lib, tools_export_lib, tools_export_plugins_lib, ], ) test( 'Tools.Export', nunit_console, args: tests_tools_export_lib, env: test_env, ) tests_util_lib = library( 'BlessTests.Util', files( 'util/ByteArrayTests.cs', 'util/DequeTests.cs', 'util/IntervalTreeTests.cs', 'util/ListTests.cs', 'util/RangeTests.cs', 'util/RedBlackTreeTests.cs', ), dependencies: nunit_dep, link_with: [ util_lib, ], ) test( 'Util', nunit_console, args: tests_util_lib, env: test_env, ) endif bless-0.6.3/tests/tools/000077500000000000000000000000001374060072200151335ustar00rootroot00000000000000bless-0.6.3/tests/tools/export/000077500000000000000000000000001374060072200164545ustar00rootroot00000000000000bless-0.6.3/tests/tools/export/ExporterTests.cs000066400000000000000000000037171374060072200216460ustar00rootroot00000000000000/* * Copyright (c) 2006, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using NUnit.Framework; using System; using System.IO; using System.Text; using Bless.Tools.Export; using Bless.Tools.Export.Plugins; using Bless.Buffers; namespace BlessTests.Export { [TestFixture] public class ExporterTests { [Test] public void AppendTest() { string correct = "0000: __| __|0x02|0x03 - \n" + "0004: 0x04|0x05|0x06|0x07 - 04*05*\n" + "0008: 0x08|0x09|0x0A|0x0B - 08*09*\n" + "000C: 0x0C|0x0D|0x0E|0x10 - 0C*0D*\n" + "0010: 0x10|0x11|0x12|0x13 - 10*11*\n" + "0014: 0x14| __| __| __ - 14* \n"; MemoryStream ms = new MemoryStream(); TextExportBuilder teb = new TextExportBuilder(ms); InterpretedPatternExporter ipe = new InterpretedPatternExporter(teb); IBuffer buffer = new SimpleBuffer(); buffer.Append(new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 16, 17, 18, 19, 20}, 0, 21); ipe.Pattern = "%A\"4\"%[%O\"4\"%: %E\"4\"e\"_\"p\"0x\"x\"|\"%] - %E\"2\"s\"*\"%%I\"2\"%\n"; bool cancelled = false; ipe.Export(buffer, 2, buffer.Size - 1, ref cancelled); Assert.AreEqual(correct, ASCIIEncoding.ASCII.GetString(ms.ToArray()), "#1"); } } } // end namespace bless-0.6.3/tests/util/000077500000000000000000000000001374060072200147505ustar00rootroot00000000000000bless-0.6.3/tests/util/BaseConverterTests.cs000066400000000000000000000046721374060072200210750ustar00rootroot00000000000000// created on 3/8/2005 at 5:19 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using NUnit.Framework; using System; using Bless.Util; namespace BlessTests.Util { [TestFixture] public class BaseConverterTests { [Test] public void BaseConverterTest1() { string s2 = BaseConverter.ConvertToString(15464, 2); string s8 = BaseConverter.ConvertToString(15464, 8); string s10 = BaseConverter.ConvertToString(15464, 10); string s16 = BaseConverter.ConvertToString(15464, 16); Assert.AreEqual("11110001101000", s2, "#base2"); Assert.AreEqual("36150", s8, "#base8"); Assert.AreEqual("15464", s10, "#base10"); Assert.AreEqual("3C68", s16, "#base16"); } [Test] public void BaseConverterTest2() { long l2 = BaseConverter.ConvertToNum("11110001101000", 2); long l8 = BaseConverter.ConvertToNum("36150", 8); long l10 = BaseConverter.ConvertToNum("15464", 10); long l16 = BaseConverter.ConvertToNum("3C68", 16); Assert.AreEqual(15464, l2, "#base2"); Assert.AreEqual(15464, l8, "#base8"); Assert.AreEqual(15464, l10, "#base10"); Assert.AreEqual(15464, l16, "#base16"); } [Test] [ExpectedException(typeof(FormatException))] public void BaseConverterTest3() { BaseConverter.ConvertToNum("18032", 8); } [Test] [ExpectedException(typeof(FormatException))] public void BaseConverterTest4() { BaseConverter.ConvertToNum("a04zd", 16); } [Test] public void BaseConverterTest5() { long l16 = BaseConverter.Parse(" 0x66 "); long l10 = BaseConverter.Parse(" 66 "); long l8 = BaseConverter.Parse(" 066 "); Assert.AreEqual(0x66, l16, "#base16"); Assert.AreEqual(66, l10, "#base10"); Assert.AreEqual(54, l8, "#base8"); } } } // end namespace bless-0.6.3/tests/util/ByteArrayTests.cs000066400000000000000000000050541374060072200202300ustar00rootroot00000000000000// created on 3/8/2005 at 5:19 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using NUnit.Framework; using System; using Bless.Util; namespace BlessTests.Util { [TestFixture] public class ByteArrayTests { [Test] public void ByteArrayHexTest1() { byte[] ba = ByteArray.FromString("0305ffFa66", 16); Assert.AreEqual(5, ba.Length, "#Length"); Assert.AreEqual(0x03, ba[0], "#0"); Assert.AreEqual(0x05, ba[1], "#1"); Assert.AreEqual(0xff, ba[2], "#2"); Assert.AreEqual(0xfa, ba[3], "#3"); Assert.AreEqual(0x66, ba[4], "#4"); } [Test] public void ByteArrayHexTest2() { byte[] ba = ByteArray.FromString(" 63a5 fe DD Cb ", 16); Assert.AreEqual(5, ba.Length, "#Length"); Assert.AreEqual(0x63, ba[0], "#0"); Assert.AreEqual(0xa5, ba[1], "#1"); Assert.AreEqual(0xfe, ba[2], "#2"); Assert.AreEqual(0xdd, ba[3], "#3"); Assert.AreEqual(0xcb, ba[4], "#4"); } [Test] public void ByteArrayHexTest3() { byte[] ba = ByteArray.FromString(" 63a fe DDCb ", 16); Assert.AreEqual(5, ba.Length, "#Length"); Assert.AreEqual(0x63, ba[0], "#0"); Assert.AreEqual(0x0a, ba[1], "#1"); Assert.AreEqual(0xfe, ba[2], "#2"); Assert.AreEqual(0xdd, ba[3], "#3"); Assert.AreEqual(0xcb, ba[4], "#4"); } [Test] [ExpectedException(typeof(FormatException))] public void ByteArrayHexTest4() { ByteArray.FromString(" 63 a5 fg DD Cb ", 16); } [Test] public void ByteArrayHexTest5() { string s = ByteArray.ToString(new byte[]{0x63, 0xff, 0x12, 0x00, 0xca}, 16); Assert.AreEqual(14, s.Length, "#Length"); Assert.AreEqual(s, "63 FF 12 00 CA", "#0"); } [Test] public void ByteArrayStringWithShortNumbers() { byte[] ba = ByteArray.FromString("0 0 2 0 0 0 209 1", 10); Assert.AreEqual(new byte[]{0, 0, 2, 0, 0, 0, 209, 1}, ba, "#Contents"); } } } // end namespace bless-0.6.3/tests/util/DequeTests.cs000066400000000000000000000061621374060072200173720ustar00rootroot00000000000000// created on 7/4/2005 at 12:38 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using NUnit.Framework; using System; using Bless.Util; namespace BlessTests.Util { [TestFixture] public class DequeTests { [Test] public void CountTest() { Deque d = new Deque(); d.AddFront(4); d.AddFront(5); d.AddFront(6); d.AddFront(7); Assert.AreEqual(4, d.Count); } [Test] public void RemoveEndTest() { Deque d = new Deque(); d.AddFront(4); d.AddFront(5); d.AddFront(6); d.AddFront(7); Assert.AreEqual(4, (int)d.RemoveEnd()); Assert.AreEqual(5, (int)d.RemoveEnd()); Assert.AreEqual(6, (int)d.RemoveEnd()); Assert.AreEqual(7, (int)d.RemoveEnd()); } [Test] public void RemoveFrontTest() { Deque d = new Deque(); d.AddFront(4); d.AddFront(5); d.AddFront(6); d.AddFront(7); Assert.AreEqual(7, (int)d.RemoveFront()); Assert.AreEqual(6, (int)d.RemoveFront()); Assert.AreEqual(5, (int)d.RemoveFront()); Assert.AreEqual(4, (int)d.RemoveFront()); } [Test] public void MixedTest() { Deque d = new Deque(); d.AddFront(5); d.AddEnd(6); d.AddFront(4); d.AddEnd(7); Assert.AreEqual(7, (int)d.RemoveEnd()); Assert.AreEqual(4, (int)d.RemoveFront()); Assert.AreEqual(6, (int)d.RemoveEnd()); Assert.AreEqual(5, (int)d.RemoveFront()); } [Test] public void PeekTest() { Deque d = new Deque(); d.AddEnd(4); d.AddEnd(5); d.AddEnd(6); d.AddEnd(7); Assert.AreEqual(7, (int)d.PeekEnd()); Assert.AreEqual(7, (int)d.PeekEnd()); Assert.AreEqual(4, (int)d.PeekFront()); Assert.AreEqual(4, (int)d.PeekFront()); d.RemoveEnd(); Assert.AreEqual(6, (int)d.PeekEnd()); d.RemoveFront(); Assert.AreEqual(5, (int)d.PeekFront()); } [Test] public void ClearTest() { Deque d = new Deque(); d.AddEnd(4); d.AddEnd(5); d.AddEnd(6); d.AddEnd(7); Assert.AreEqual(7, (int)d.PeekEnd()); Assert.AreEqual(4, (int)d.PeekFront()); d.Clear(); Assert.AreEqual(0, d.Count); } [Test] public void NullTest() { Deque d = new Deque(); Assert.IsNull(d.RemoveFront(), "#1"); object o = new object(); d.AddEnd(o); Assert.AreEqual(o, d.RemoveEnd(), "#2"); Assert.IsNull(d.RemoveEnd(), "#3"); d.AddFront(o); Assert.AreEqual(o, d.RemoveFront(), "#4"); Assert.IsNull(d.RemoveFront(), "#5"); } } } // end namespace bless-0.6.3/tests/util/IntervalTreeTests.cs000066400000000000000000000120301374060072200207220ustar00rootroot00000000000000/* * Copyright (c) 2008, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.Collections.Generic; using NUnit.Framework; using Bless.Util; using Range = Bless.Util.Range; namespace BlessTests.Util { [TestFixture()] public class IntervalTreeTests { [Test()] public void ITInsertTest() { IntervalTree t = new IntervalTree(); t.Insert(new Range(5,55)); IList result = t.SearchOverlap(new Range(0, 4)); Assert.AreEqual(0, result.Count, "#1"); result = t.SearchOverlap(new Range(4, 13)); Assert.AreEqual(1, result.Count, "#2"); Assert.AreEqual(55, result[0].End, "#2.1"); result = t.SearchOverlap(new Range(57, 68)); Assert.AreEqual(0, result.Count, "#3"); result = t.SearchOverlap(new Range(3,100)); Assert.AreEqual(1, result.Count, "#4"); Assert.AreEqual(55, result[0].End, "#2.1"); } [Test()] public void ITSearchTest() { IntervalTree t = new IntervalTree(); for (int i = 0; i < 1000; i += 4) { t.Insert(new Range(i, i + 2)); } for (int i = 0 ; i < 1000; i += 8) { IList result = t.SearchOverlap(new Range(i, i + 7)); Assert.AreEqual(2, result.Count, "#1."+i.ToString()); } for (int i = 2 ; i < 1000; i += 4) { IList result = t.SearchOverlap(new Range(i+1, i + 1)); Assert.AreEqual(0, result.Count, "#2."+i.ToString()); } { IList result = t.SearchOverlap(new Range(0, 1050)); Assert.AreEqual(250, result.Count, "#3"); } } [Test()] public void ITDuplicateTest() { IntervalTree t = new IntervalTree(); for (int i = 0; i < 1000; i += 1) { t.Insert(new Range(0, i)); } for (int i = 0 ; i <= 1000; i++) { IList result = t.SearchOverlap(new Range(i, i)); Assert.AreEqual(1000 - i, result.Count, "#1."+i.ToString()); } } [Test()] public void ITDeleteTest() { IntervalTree t = new IntervalTree(); for (int i = 0; i < 1000; i += 4) { t.Insert(new Range(i, i + 2)); } for (int i = 0 ; i < 1000; i += 8) { IList result = t.SearchOverlap(new Range(i, i + 7)); Assert.AreEqual(2, result.Count, "#1."+i.ToString()); t.Delete(new Range(i, i+2)); result = t.SearchOverlap(new Range(i, i + 7)); Assert.AreEqual(1, result.Count, "#2."+i.ToString()); t.Delete(new Range(i+2, i+4)); result = t.SearchOverlap(new Range(i, i + 7)); Assert.AreEqual(1, result.Count, "#3."+i.ToString()); t.Delete(new Range(i+4, i+6)); result = t.SearchOverlap(new Range(i, i + 7)); Assert.AreEqual(0, result.Count, "#4."+i.ToString()); t.Delete(new Range(i+6, i+8)); result = t.SearchOverlap(new Range(i, i + 7)); Assert.AreEqual(0, result.Count, "#5."+i.ToString()); } } [Test()] public void ITDeleteDuplicateTest() { IntervalTree t = new IntervalTree(); for (int i = 0; i < 1000; i += 4) { t.Insert(new Range(i, i + 3)); t.Insert(new Range(i, i + 3)); t.Insert(new Range(i, i + 3)); } for (int i = 0; i < 1000; i += 8) { IList result = t.SearchOverlap(new Range(i, i + 7)); Assert.AreEqual(6, result.Count, "#5."+i.ToString()); t.Delete(new Range(i, i+3)); result = t.SearchOverlap(new Range(i, i + 7)); Assert.AreEqual(5, result.Count, "#5."+i.ToString()); t.Delete(new Range(i, i+3)); result = t.SearchOverlap(new Range(i, i + 7)); Assert.AreEqual(4, result.Count, "#5."+i.ToString()); t.Delete(new Range(i, i+3)); result = t.SearchOverlap(new Range(i, i + 7)); Assert.AreEqual(3, result.Count, "#5."+i.ToString()); t.Delete(new Range(i, i+3)); result = t.SearchOverlap(new Range(i, i + 7)); Assert.AreEqual(3, result.Count, "#5."+i.ToString()); t.Delete(new Range(i+4, i+7)); result = t.SearchOverlap(new Range(i, i + 7)); Assert.AreEqual(2, result.Count, "#5."+i.ToString()); t.Delete(new Range(i+4, i+7)); result = t.SearchOverlap(new Range(i, i + 7)); Assert.AreEqual(1, result.Count, "#5."+i.ToString()); t.Delete(new Range(i+4, i+7)); result = t.SearchOverlap(new Range(i, i + 7)); Assert.AreEqual(0, result.Count, "#5."+i.ToString()); } } } } bless-0.6.3/tests/util/ListTests.cs000066400000000000000000000063361374060072200172450ustar00rootroot00000000000000// created on 3/8/2005 at 5:19 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using NUnit.Framework; using System; using Bless.Util; namespace BlessTests.Util { [TestFixture] public class ListTests { [Test] public void AppendTest() { List list = new List(); list.Append(4); list.Append(7); List.Node n = list.First; Assert.AreEqual(4, n.data); Assert.AreEqual(7, n.next.data); } [Test] public void CountTest() { List list = new List(); list.Append(1); list.Append(2); list.Append(3); Assert.AreEqual(3, list.Count); } [Test] public void InsertBeforeTest() { List list = new List(); list.InsertBefore(list.First, 3); list.InsertBefore(list.First, 1); list.InsertBefore(list.Last, 2); List.Node n = list.First; Assert.AreEqual(1, n.data); Assert.AreEqual(2, n.next.data); Assert.AreEqual(3, n.next.next.data); } [Test] public void InsertAfterTest() { List list = new List(); list.InsertAfter(list.First, 1); list.InsertAfter(list.Last, 3); list.InsertAfter(list.First, 2); List.Node n = list.First; Assert.AreEqual(1, n.data); Assert.AreEqual(2, n.next.data); Assert.AreEqual(3, n.next.next.data); } [Test] public void IndexerTest() { List list = new List(); list.Append(1); list.Append(2); list.Append(3); Assert.AreEqual(1, list[0]); Assert.AreEqual(2, list[1]); Assert.AreEqual(3, list[2]); //if (list[3]!=null) //Assert.Fail("Expected: null!"); } [Test] public void RemoveTest() { List list = new List(); List.Node n1 = list.Append(1); list.Append(2); List.Node n3 = list.Append(3); List.Node n4 = list.Append(4); list.Remove(n1); Assert.AreEqual(3, list.Count, "#1"); Assert.AreEqual(2, list[0], "#2"); Assert.AreEqual(3, list[1], "#3"); Assert.AreEqual(4, list[2], "#4"); list.Remove(n3); Assert.AreEqual(2, list.Count, "#5"); Assert.AreEqual(2, list[0], "#6"); Assert.AreEqual(4, list[1], "#7"); list.Remove(n4); Assert.AreEqual(1, list.Count, "#8"); Assert.AreEqual(2, list[0], "#9"); //if (list[3]!=null) //Assert.Fail("Expected: null!"); } [Test] public void RemoveLastTest() { List list = new List(); list.Append(1); List.Node n2 = list.Append(2); list.Remove(n2); list.Append(3); Assert.AreEqual(2, list.Count, "#1"); Assert.AreEqual(1, list[0], "#2"); Assert.AreEqual(3, list[1], "#3"); } } } // end namespace bless-0.6.3/tests/util/RangeTests.cs000066400000000000000000000071201374060072200173560ustar00rootroot00000000000000// created on 3/8/2005 at 5:20 PM /* * Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using NUnit.Framework; using System; using Bless.Util; using Range = Bless.Util.Range; namespace BlessTests.Util { [TestFixture] public class RangeTests { [Test] public void IntersectTest() { Range r1 = new Range(5, 10); Range r2 = new Range(6, 9); r1.Intersect(r2); Assert.AreEqual(6, r1.Start); Assert.AreEqual(9, r1.End); Range r3 = new Range(5, 10); Range r4 = new Range(4, 8); r3.Intersect(r4); Assert.AreEqual(5, r3.Start); Assert.AreEqual(8, r4.End); Range r5 = new Range(5, 10); Range r6 = new Range(10, 14); r5.Intersect(r6); Assert.AreEqual(10, r5.Start); Assert.AreEqual(10, r5.End); } [Test] public void DifferenceTest() { Range r1 = new Range(5, 10); Range r2 = new Range(6, 9); Range r3 = new Range(); r1.Difference(r2, r3); Assert.AreEqual(5, r1.Start, "#1"); Assert.AreEqual(5, r1.End, "#2"); Assert.AreEqual(10, r3.Start, "#3"); Assert.AreEqual(10, r3.End, "#4"); Range r4 = new Range(5, 10); Range r5 = new Range(5, 8); r4.Difference(r5, r3); Assert.AreEqual(9, r4.Start, "#5"); Assert.AreEqual(10, r4.End, "#6"); Assert.AreEqual(true, r3.IsEmpty(), "#7"); } [Test] public void SplitAtomicTest() { Range r = new Range(0, 10); Range s = new Range(4, 6); Range[] ra = new Range[]{new Range(), new Range(), new Range()}; Assert.IsTrue(r.Equals(new Range(0, 10)), "#0"); Range.SplitAtomic(ra, r, s); Assert.AreEqual(new Range(0, 3), ra[0], "#1.0"); Assert.AreEqual(new Range(4, 6), ra[1], "#1.1"); Assert.AreEqual(new Range(7, 10), ra[2], "#1.2"); s = new Range(0, 4); Range.SplitAtomic(ra, r, s); Assert.AreEqual(new Range(), ra[0], "#2.0"); Assert.AreEqual(new Range(0, 4), ra[1], "#2.1"); Assert.AreEqual(new Range(5, 10), ra[2], "#2.2"); s = new Range(6, 10); Range.SplitAtomic(ra, r, s); Assert.AreEqual(new Range(0, 5), ra[0], "#3.0"); Assert.AreEqual(new Range(6, 10), ra[1], "#3.1"); Assert.AreEqual(new Range(), ra[2], "#3.2"); s = new Range(0, 10); Range.SplitAtomic(ra, r, s); Assert.AreEqual(new Range(), ra[0], "#4.0"); Assert.AreEqual(new Range(0, 10), ra[1], "#4.1"); Assert.AreEqual(new Range(), ra[2], "#4.2"); } [Test] public void SplitAtomic1Test() { Range r = new Range(10, 20); Range s = new Range(8, 13); Range[] ra = new Range[]{new Range(), new Range(), new Range()}; Range.SplitAtomic(ra, r, s); Assert.AreEqual(new Range(), ra[0], "#1.0"); Assert.AreEqual(new Range(8, 13), ra[1], "#1.1"); Assert.AreEqual(new Range(14, 20), ra[2], "#1.2"); s = new Range(16, 26); Range.SplitAtomic(ra, r, s); Assert.AreEqual(new Range(10, 15), ra[0], "#2.0"); Assert.AreEqual(new Range(16, 26), ra[1], "#2.1"); Assert.AreEqual(new Range(), ra[2], "#2.2"); } } } // end namespace bless-0.6.3/tests/util/RedBlackTreeTests.cs000066400000000000000000000126251374060072200206170ustar00rootroot00000000000000// Created 12:17 PM 16/3/2008 /* * Copyright (c) 2008, Alexandros Frantzis (alf82 [at] freemail [dot] gr) * * This file is part of Bless. * * Bless 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. * * Bless 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 Bless; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using NUnit.Framework; using Bless.Util; using System.Collections.Generic; namespace BlessTests.Util { [TestFixture()] public class RedBlackTreeTests { [Test()] public void RBInsertTest() { RedBlackTree rb = new RedBlackTree(); rb.Insert(5, "5"); IList result = rb.Search(5); Assert.AreEqual("5", result[0], "#1"); result = rb.Search(8); Assert.AreEqual(0, result.Count, "#1"); rb.Insert(100, "100"); result = rb.Search(100); Assert.AreEqual("100", result[0], "#3"); result = rb.Search(5); Assert.AreEqual("5", result[0], "#4"); } [Test()] public void RBSearchTest() { RedBlackTree rb = new RedBlackTree(); for (int i = 0; i < 10000; i += 2) { rb.Insert(i, i.ToString()); } for (int i = 0; i < 10000; i++) { IList result = rb.Search(i); if ( i % 2 == 0) Assert.AreEqual(i.ToString(), result[0], i.ToString()); else Assert.AreEqual(0, result.Count, i.ToString()); } } [Test()] public void RBDuplicateTest() { RedBlackTree rb = new RedBlackTree(); for (int i = 0; i < 1000; i++) { rb.Insert(0, i.ToString()); } IList result = rb.Search(0); Assert.AreEqual(1000, result.Count, "#1"); } [Test()] public void RBDeleteTest() { RedBlackTree rb = new RedBlackTree(); rb.Insert(0, "0"); IList result = rb.Search(0); Assert.AreEqual(1, result.Count, "#1"); Assert.AreEqual("0", result[0], "#1.1"); rb.Delete(0); result = rb.Search(0); Assert.AreEqual(0, result.Count, "#2"); rb.Delete(0); } [Test()] public void RBDelete1Test() { RedBlackTree rb = new RedBlackTree(); for (int i = 0; i < 10; i++) { rb.Insert(i, i.ToString()); } for (int i = 0; i < 10; i++) { IList result = rb.Search(i); Assert.AreEqual(1, result.Count, "#1.1:" + i.ToString()); Assert.AreEqual(i.ToString(), result[0], "#1.2:" + i.ToString()); } for (int i = 0; i < 10; i+=2) { rb.Delete(i); } for (int i = 0; i < 10; i++) { IList result = rb.Search(i); if (i % 2 == 0) Assert.AreEqual(0, result.Count, "#2.1:" + i.ToString()); else { Assert.AreEqual(1, result.Count, "#2.2:" + i.ToString()); Assert.AreEqual(i.ToString(), result[0], "#2.3:" + i.ToString()); } } } private void RBAssertPresent(RedBlackTree rb, int s, int e) { for (int i = s; i <= e; i++) { IList result = rb.Search(i); Assert.AreEqual(1, result.Count, string.Format("#{0}->{1}@{2}", s, e, i)); Assert.AreEqual(i.ToString(), result[0], string.Format("#{0}->{1}@{2}", s, e, i)); } } private void RBAssertNotPresent(RedBlackTree rb, int s, int e) { for (int i = s; i <= e; i++) { IList result = rb.Search(i); Assert.AreEqual(0, result.Count, string.Format("#!{0}->{1}@{2}", s, e, i)); } } [Test()] public void RBDelete2Test() { RedBlackTree rb = new RedBlackTree(); for (int i = 19; i >= 0; i--) { rb.Insert(i, i.ToString()); } for (int i = 0; i < 10; i++) { rb.Delete(9 - i); RBAssertPresent(rb, 0, 9 - i - 1); RBAssertPresent(rb, 10 + i, 19); RBAssertNotPresent(rb, 9 - i, 10 + i - 1); rb.Delete(10 + i); RBAssertPresent(rb, 0, 9 - i - 1); RBAssertPresent(rb, 10 + i + 1, 19); RBAssertNotPresent(rb, 9 - i, 10 + i ); } } [Test()] public void RBDelete3Test() { RedBlackTree rb = new RedBlackTree(); for (int i = 99; i >= 0; i--) { rb.Insert(i, i.ToString()); } for (int i = 0; i < 50; i++) { rb.Delete(49 - i); RBAssertPresent(rb, 0, 49 - i - 1); RBAssertPresent(rb, 50 + i, 99); RBAssertNotPresent(rb, 49 - i, 50 + i - 1); rb.Delete(50 + i); RBAssertPresent(rb, 0, 49 - i - 1); RBAssertPresent(rb, 50 + i + 1, 99); RBAssertNotPresent(rb, 49 - i, 50 + i ); } } [Test()] public void RBDeleteNotPresentTest() { RedBlackTree rb = new RedBlackTree(); for (int i = 0; i < 5; i++) { rb.Insert(i, i.ToString()); } for (int i = 0; i < 5; i++) { rb.Delete(i); rb.Delete(i); } } [Test()] public void RBDeleteRandomTest() { RedBlackTree rb = new RedBlackTree(); for (int i = 99; i >= 0; i--) { rb.Insert(i, i.ToString()); } Random r = new Random(); for (int i = 0; i < 1000; i++) { int j = r.Next(0, 99); rb.Delete(j); } } } } // end namespace